From 78a47d7619bf9c3bd3167790be3dcd0e0ae0d117 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Mon, 13 Jan 2003 17:11:28 +0000 Subject: [PATCH] Algorithm improvements, free_unreachable_objects() added. [SVN r16894] --- sp_debug_hooks.cpp | 150 +++++++++++++++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 47 deletions(-) diff --git a/sp_debug_hooks.cpp b/sp_debug_hooks.cpp index 458810f..d289ba4 100644 --- a/sp_debug_hooks.cpp +++ b/sp_debug_hooks.cpp @@ -14,11 +14,12 @@ #if defined(BOOST_ENABLE_SP_DEBUG_HOOKS) #include -#include +#include #include #include #include #include +#include #include int const m = 2; // m * sizeof(int) must be aligned appropriately @@ -113,7 +114,7 @@ void * operator new[](size_t n, nothrow_t const &) throw() // cycle detection -typedef std::map< void *, std::pair > map_type; +typedef std::map< void const *, std::pair > map_type; static map_type & get_map() { @@ -151,7 +152,9 @@ namespace // assume 4 byte alignment for pointers when scanning size_t const pointer_align = 4; -static void scan_and_count(void const * area, size_t size, map_type const & m, std::map & m2) +typedef std::map 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(area); @@ -166,79 +169,132 @@ static void scan_and_count(void const * area, size_t size, map_type const & m, s } } -static bool scan_and_mark(void const * area, size_t size, map_type const & m, std::map & m2) +typedef std::deque open_type; + +static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open) { - bool updated = false; unsigned char const * p = static_cast(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(p); - if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0) + if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0) { - // mark as reachable - - if(m2[q->pn.pi] != 0) - { - updated = true; - m2[q->pn.pi] = 0; - } + open.push_back(q->pn.pi); + m2.erase(q->pn.pi); } } - - return updated; } -void report_unreachable_objects() +static void find_unreachable_objects(map_type const & m, map2_type & m2) { - std::map m2; - - mutex_type::scoped_lock lock(get_mutex()); - - map_type & m = get_map(); - // scan objects for shared_ptr members, compute internal counts - for(map_type::iterator i = m.begin(); i != m.end(); ++i) { - boost::detail::counted_base const * p = static_cast(i->first); + for(map_type::const_iterator i = m.begin(); i != m.end(); ++i) + { + boost::detail::counted_base const * p = static_cast(i->first); - BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map + 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); + scan_and_count(i->second.first, i->second.second, m, m2); + } } // mark reachable objects - bool updated; - - do { - updated = false; + open_type open; - for(map_type::iterator i = m.begin(); i != m.end(); ++i) + for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i) { - boost::detail::counted_base const * p = static_cast(i->first); - - if(p->use_count() != m2[p] && scan_and_mark(i->second.first, i->second.second, m, m2)) - { - updated = true; - } + boost::detail::counted_base const * p = static_cast(i->first); + if(p->use_count() != i->second) open.push_back(p); } - } while(updated); - - // report unreachable objects - - for(map_type::iterator i = m.begin(); i != m.end(); ++i) - { - boost::detail::counted_base const * p = static_cast(i->first); - - if(p->use_count() == m2[p]) + for(open_type::iterator j = open.begin(); j != open.end(); ++j) { - std::cerr << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n"; + 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 > 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(area); + + for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) + { + shared_ptr_layout * q = reinterpret_cast(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 * ppx = reinterpret_cast< boost::shared_ptr * >(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); } }