Moved 'garbage collector' to sp_collector.cpp, collector_test.cpp added.

[SVN r17050]
This commit is contained in:
Peter Dimov
2003-01-27 14:02:00 +00:00
parent b60de38d28
commit fabd6e5755
4 changed files with 375 additions and 199 deletions

View File

@@ -8,19 +8,12 @@
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// http://www.boost.org/libs/smart_ptr/debug_hooks.html
//
#if defined(BOOST_ENABLE_SP_DEBUG_HOOKS)
#include <boost/assert.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/detail/lightweight_mutex.hpp>
#include <new>
#include <cstdlib>
#include <map>
#include <deque>
#include <iostream>
int const m = 2; // m * sizeof(int) must be aligned appropriately
@@ -112,192 +105,6 @@ void * operator new[](size_t n, nothrow_t const &) throw()
#endif
// cycle detection
typedef std::map< void const *, std::pair<void *, size_t> > map_type;
static map_type & get_map()
{
static map_type m;
return m;
}
typedef boost::detail::lightweight_mutex mutex_type;
static mutex_type & get_mutex()
{
static mutex_type m;
return m;
}
static void * init_mutex_before_main = &get_mutex();
namespace
{
class X;
struct count_layout
{
boost::detail::sp_counted_base * pi;
int id;
};
struct shared_ptr_layout
{
X * px;
count_layout pn;
};
}
// assume 4 byte alignment for pointers when scanning
size_t const pointer_align = 4;
typedef std::map<void const *, long> map2_type;
static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2)
{
unsigned char const * p = static_cast<unsigned char const *>(area);
for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
{
shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0)
{
++m2[q->pn.pi];
}
}
}
typedef std::deque<void const *> open_type;
static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
{
unsigned char const * p = static_cast<unsigned char const *>(area);
for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
{
shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0)
{
open.push_back(q->pn.pi);
m2.erase(q->pn.pi);
}
}
}
static void find_unreachable_objects(map_type const & m, map2_type & m2)
{
// scan objects for shared_ptr members, compute internal counts
{
for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
{
boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map
scan_and_count(i->second.first, i->second.second, m, m2);
}
}
// mark reachable objects
{
open_type open;
for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
{
boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
if(p->use_count() != i->second) open.push_back(p);
}
for(open_type::iterator j = open.begin(); j != open.end(); ++j)
{
m2.erase(*j);
}
while(!open.empty())
{
void const * p = open.front();
open.pop_front();
map_type::const_iterator i = m.find(p);
BOOST_ASSERT(i != m.end());
scan_and_mark(i->second.first, i->second.second, m2, open);
}
}
// m2 now contains the unreachable objects
}
void report_unreachable_objects(bool verbose)
{
map2_type m2;
mutex_type::scoped_lock lock(get_mutex());
map_type const & m = get_map();
find_unreachable_objects(m, m2);
if(verbose)
{
for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
{
map_type::const_iterator i = m.find(j->first);
BOOST_ASSERT(i != m.end());
// std::cerr << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
}
}
if(verbose || !m2.empty())
{
std::cerr << m2.size() << " unreachable objects.\n";
}
}
typedef std::deque< boost::shared_ptr<X> > free_list_type;
static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free)
{
unsigned char * p = static_cast<unsigned char *>(area);
for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
{
shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p);
if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0)
{
boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p);
free.push_back(*ppx);
ppx->reset();
}
}
}
void free_unreachable_objects()
{
map2_type m2;
mutex_type::scoped_lock lock(get_mutex());
map_type const & m = get_map();
find_unreachable_objects(m, m2);
free_list_type free;
for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
{
map_type::const_iterator i = m.find(j->first);
BOOST_ASSERT(i != m.end());
scan_and_free(i->second.first, i->second.second, m2, free);
}
}
// debug hooks
namespace boost
@@ -317,11 +124,9 @@ void sp_scalar_constructor_hook(void * p)
*pm = adopted_scalar;
}
void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn)
void sp_scalar_constructor_hook(void * px, std::size_t, void *)
{
sp_scalar_constructor_hook(px);
mutex_type::scoped_lock lock(get_mutex());
get_map()[pn] = std::make_pair(px, size);
}
void sp_scalar_destructor_hook(void * p)
@@ -336,11 +141,9 @@ void sp_scalar_destructor_hook(void * p)
*pm = allocated_scalar;
}
void sp_scalar_destructor_hook(void * px, std::size_t /*size*/, void * pn)
void sp_scalar_destructor_hook(void * px, std::size_t, void *)
{
sp_scalar_destructor_hook(px);
mutex_type::scoped_lock lock(get_mutex());
get_map().erase(pn);
}
// It is not possible to handle the array hooks in a portable manner.