1*70f497fbSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*70f497fbSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*70f497fbSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*70f497fbSAndrew Rist * distributed with this work for additional information 6*70f497fbSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*70f497fbSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*70f497fbSAndrew Rist * "License"); you may not use this file except in compliance 9*70f497fbSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*70f497fbSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*70f497fbSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*70f497fbSAndrew Rist * software distributed under the License is distributed on an 15*70f497fbSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*70f497fbSAndrew Rist * KIND, either express or implied. See the License for the 17*70f497fbSAndrew Rist * specific language governing permissions and limitations 18*70f497fbSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*70f497fbSAndrew Rist *************************************************************/ 21*70f497fbSAndrew Rist 22*70f497fbSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir 25cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 26cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 27cdf0e10cSrcweir // 28cdf0e10cSrcweir // sp_collector.cpp 29cdf0e10cSrcweir // 30cdf0e10cSrcweir // Copyright (c) 2002, 2003 Peter Dimov 31cdf0e10cSrcweir // 32cdf0e10cSrcweir // Permission to copy, use, modify, sell and distribute this software 33cdf0e10cSrcweir // is granted provided this copyright notice appears in all copies. 34cdf0e10cSrcweir // This software is provided "as is" without express or implied 35cdf0e10cSrcweir // warranty, and with no claim as to its suitability for any purpose. 36cdf0e10cSrcweir // 37cdf0e10cSrcweir 38cdf0e10cSrcweir #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS) 39cdf0e10cSrcweir 40cdf0e10cSrcweir #include <boost/assert.hpp> 41cdf0e10cSrcweir #include <boost/shared_ptr.hpp> 42cdf0e10cSrcweir #include <boost/detail/lightweight_mutex.hpp> 43cdf0e10cSrcweir #include <cstdlib> 44cdf0e10cSrcweir #include <map> 45cdf0e10cSrcweir #include <deque> 46cdf0e10cSrcweir #include <iostream> 47cdf0e10cSrcweir 48cdf0e10cSrcweir typedef std::map< void const *, std::pair<void *, size_t> > map_type; 49cdf0e10cSrcweir 50cdf0e10cSrcweir static map_type & get_map() 51cdf0e10cSrcweir { 52cdf0e10cSrcweir static map_type m; 53cdf0e10cSrcweir return m; 54cdf0e10cSrcweir } 55cdf0e10cSrcweir 56cdf0e10cSrcweir typedef boost::detail::lightweight_mutex mutex_type; 57cdf0e10cSrcweir 58cdf0e10cSrcweir static mutex_type & get_mutex() 59cdf0e10cSrcweir { 60cdf0e10cSrcweir static mutex_type m; 61cdf0e10cSrcweir return m; 62cdf0e10cSrcweir } 63cdf0e10cSrcweir 64cdf0e10cSrcweir static void * init_mutex_before_main = &get_mutex(); 65cdf0e10cSrcweir 66cdf0e10cSrcweir namespace 67cdf0e10cSrcweir { 68cdf0e10cSrcweir class X; 69cdf0e10cSrcweir 70cdf0e10cSrcweir struct count_layout 71cdf0e10cSrcweir { 72cdf0e10cSrcweir boost::detail::sp_counted_base * pi; 73cdf0e10cSrcweir int id; 74cdf0e10cSrcweir }; 75cdf0e10cSrcweir 76cdf0e10cSrcweir struct shared_ptr_layout 77cdf0e10cSrcweir { 78cdf0e10cSrcweir X * px; 79cdf0e10cSrcweir count_layout pn; 80cdf0e10cSrcweir }; 81cdf0e10cSrcweir } 82cdf0e10cSrcweir 83cdf0e10cSrcweir // assume 4 byte alignment for pointers when scanning 84cdf0e10cSrcweir size_t const pointer_align = 4; 85cdf0e10cSrcweir 86cdf0e10cSrcweir typedef std::map<void const *, long> map2_type; 87cdf0e10cSrcweir 88cdf0e10cSrcweir static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2) 89cdf0e10cSrcweir { 90cdf0e10cSrcweir unsigned char const * p = static_cast<unsigned char const *>(area); 91cdf0e10cSrcweir 92cdf0e10cSrcweir for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) 93cdf0e10cSrcweir { 94cdf0e10cSrcweir shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p); 95cdf0e10cSrcweir 96cdf0e10cSrcweir if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0) 97cdf0e10cSrcweir { 98cdf0e10cSrcweir ++m2[q->pn.pi]; 99cdf0e10cSrcweir } 100cdf0e10cSrcweir } 101cdf0e10cSrcweir } 102cdf0e10cSrcweir 103cdf0e10cSrcweir typedef std::deque<void const *> open_type; 104cdf0e10cSrcweir 105cdf0e10cSrcweir static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open) 106cdf0e10cSrcweir { 107cdf0e10cSrcweir unsigned char const * p = static_cast<unsigned char const *>(area); 108cdf0e10cSrcweir 109cdf0e10cSrcweir for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) 110cdf0e10cSrcweir { 111cdf0e10cSrcweir shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p); 112cdf0e10cSrcweir 113cdf0e10cSrcweir if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0) 114cdf0e10cSrcweir { 115cdf0e10cSrcweir open.push_back(q->pn.pi); 116cdf0e10cSrcweir m2.erase(q->pn.pi); 117cdf0e10cSrcweir } 118cdf0e10cSrcweir } 119cdf0e10cSrcweir } 120cdf0e10cSrcweir 121cdf0e10cSrcweir static void find_unreachable_objects_impl(map_type const & m, map2_type & m2) 122cdf0e10cSrcweir { 123cdf0e10cSrcweir // scan objects for shared_ptr members, compute internal counts 124cdf0e10cSrcweir 125cdf0e10cSrcweir { 126cdf0e10cSrcweir std::cout << "... " << m.size() << " objects in m.\n"; 127cdf0e10cSrcweir 128cdf0e10cSrcweir for(map_type::const_iterator i = m.begin(); i != m.end(); ++i) 129cdf0e10cSrcweir { 130cdf0e10cSrcweir BOOST_ASSERT(static_cast<boost::detail::sp_counted_base const *>(i->first)->use_count() != 0); // there should be no inactive counts in the map 131cdf0e10cSrcweir 132cdf0e10cSrcweir scan_and_count(i->second.first, i->second.second, m, m2); 133cdf0e10cSrcweir } 134cdf0e10cSrcweir 135cdf0e10cSrcweir std::cout << "... " << m2.size() << " objects in m2.\n"; 136cdf0e10cSrcweir } 137cdf0e10cSrcweir 138cdf0e10cSrcweir // mark reachable objects 139cdf0e10cSrcweir 140cdf0e10cSrcweir { 141cdf0e10cSrcweir open_type open; 142cdf0e10cSrcweir 143cdf0e10cSrcweir for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i) 144cdf0e10cSrcweir { 145cdf0e10cSrcweir boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first); 146cdf0e10cSrcweir if(p->use_count() != i->second) open.push_back(p); 147cdf0e10cSrcweir } 148cdf0e10cSrcweir 149cdf0e10cSrcweir std::cout << "... " << m2.size() << " objects in open.\n"; 150cdf0e10cSrcweir 151cdf0e10cSrcweir for(open_type::iterator j = open.begin(); j != open.end(); ++j) 152cdf0e10cSrcweir { 153cdf0e10cSrcweir m2.erase(*j); 154cdf0e10cSrcweir } 155cdf0e10cSrcweir 156cdf0e10cSrcweir while(!open.empty()) 157cdf0e10cSrcweir { 158cdf0e10cSrcweir void const * p = open.front(); 159cdf0e10cSrcweir open.pop_front(); 160cdf0e10cSrcweir 161cdf0e10cSrcweir map_type::const_iterator i = m.find(p); 162cdf0e10cSrcweir BOOST_ASSERT(i != m.end()); 163cdf0e10cSrcweir 164cdf0e10cSrcweir scan_and_mark(i->second.first, i->second.second, m2, open); 165cdf0e10cSrcweir } 166cdf0e10cSrcweir } 167cdf0e10cSrcweir 168cdf0e10cSrcweir // m2 now contains the unreachable objects 169cdf0e10cSrcweir } 170cdf0e10cSrcweir 171cdf0e10cSrcweir std::size_t find_unreachable_objects(bool report) 172cdf0e10cSrcweir { 173cdf0e10cSrcweir map2_type m2; 174cdf0e10cSrcweir 175cdf0e10cSrcweir #ifdef BOOST_HAS_THREADS 176cdf0e10cSrcweir 177cdf0e10cSrcweir // This will work without the #ifdef, but some compilers warn 178cdf0e10cSrcweir // that lock is not referenced 179cdf0e10cSrcweir 180cdf0e10cSrcweir mutex_type::scoped_lock lock(get_mutex()); 181cdf0e10cSrcweir 182cdf0e10cSrcweir #endif 183cdf0e10cSrcweir 184cdf0e10cSrcweir map_type const & m = get_map(); 185cdf0e10cSrcweir 186cdf0e10cSrcweir find_unreachable_objects_impl(m, m2); 187cdf0e10cSrcweir 188cdf0e10cSrcweir if(report) 189cdf0e10cSrcweir { 190cdf0e10cSrcweir for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j) 191cdf0e10cSrcweir { 192cdf0e10cSrcweir map_type::const_iterator i = m.find(j->first); 193cdf0e10cSrcweir BOOST_ASSERT(i != m.end()); 194cdf0e10cSrcweir std::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n"; 195cdf0e10cSrcweir } 196cdf0e10cSrcweir } 197cdf0e10cSrcweir 198cdf0e10cSrcweir return m2.size(); 199cdf0e10cSrcweir } 200cdf0e10cSrcweir 201cdf0e10cSrcweir typedef std::deque< boost::shared_ptr<X> > free_list_type; 202cdf0e10cSrcweir 203cdf0e10cSrcweir static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free) 204cdf0e10cSrcweir { 205cdf0e10cSrcweir unsigned char * p = static_cast<unsigned char *>(area); 206cdf0e10cSrcweir 207cdf0e10cSrcweir for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align) 208cdf0e10cSrcweir { 209cdf0e10cSrcweir shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p); 210cdf0e10cSrcweir 211cdf0e10cSrcweir if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0) 212cdf0e10cSrcweir { 213cdf0e10cSrcweir boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p); 214cdf0e10cSrcweir free.push_back(*ppx); 215cdf0e10cSrcweir ppx->reset(); 216cdf0e10cSrcweir } 217cdf0e10cSrcweir } 218cdf0e10cSrcweir } 219cdf0e10cSrcweir 220cdf0e10cSrcweir void free_unreachable_objects() 221cdf0e10cSrcweir { 222cdf0e10cSrcweir free_list_type free; 223cdf0e10cSrcweir 224cdf0e10cSrcweir { 225cdf0e10cSrcweir map2_type m2; 226cdf0e10cSrcweir 227cdf0e10cSrcweir #ifdef BOOST_HAS_THREADS 228cdf0e10cSrcweir 229cdf0e10cSrcweir mutex_type::scoped_lock lock(get_mutex()); 230cdf0e10cSrcweir 231cdf0e10cSrcweir #endif 232cdf0e10cSrcweir 233cdf0e10cSrcweir map_type const & m = get_map(); 234cdf0e10cSrcweir 235cdf0e10cSrcweir find_unreachable_objects_impl(m, m2); 236cdf0e10cSrcweir 237cdf0e10cSrcweir for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j) 238cdf0e10cSrcweir { 239cdf0e10cSrcweir map_type::const_iterator i = m.find(j->first); 240cdf0e10cSrcweir BOOST_ASSERT(i != m.end()); 241cdf0e10cSrcweir scan_and_free(i->second.first, i->second.second, m2, free); 242cdf0e10cSrcweir } 243cdf0e10cSrcweir } 244cdf0e10cSrcweir 245cdf0e10cSrcweir std::cout << "... about to free " << free.size() << " objects.\n"; 246cdf0e10cSrcweir } 247cdf0e10cSrcweir 248cdf0e10cSrcweir // debug hooks 249cdf0e10cSrcweir 250cdf0e10cSrcweir namespace boost 251cdf0e10cSrcweir { 252cdf0e10cSrcweir 253cdf0e10cSrcweir void sp_scalar_constructor_hook(void *) 254cdf0e10cSrcweir { 255cdf0e10cSrcweir } 256cdf0e10cSrcweir 257cdf0e10cSrcweir void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn) 258cdf0e10cSrcweir { 259cdf0e10cSrcweir #ifdef BOOST_HAS_THREADS 260cdf0e10cSrcweir 261cdf0e10cSrcweir mutex_type::scoped_lock lock(get_mutex()); 262cdf0e10cSrcweir 263cdf0e10cSrcweir #endif 264cdf0e10cSrcweir 265cdf0e10cSrcweir get_map()[pn] = std::make_pair(px, size); 266cdf0e10cSrcweir } 267cdf0e10cSrcweir 268cdf0e10cSrcweir void sp_scalar_destructor_hook(void *) 269cdf0e10cSrcweir { 270cdf0e10cSrcweir } 271cdf0e10cSrcweir 272cdf0e10cSrcweir void sp_scalar_destructor_hook(void *, std::size_t, void * pn) 273cdf0e10cSrcweir { 274cdf0e10cSrcweir #ifdef BOOST_HAS_THREADS 275cdf0e10cSrcweir 276cdf0e10cSrcweir mutex_type::scoped_lock lock(get_mutex()); 277cdf0e10cSrcweir 278cdf0e10cSrcweir #endif 279cdf0e10cSrcweir 280cdf0e10cSrcweir get_map().erase(pn); 281cdf0e10cSrcweir } 282cdf0e10cSrcweir 283cdf0e10cSrcweir void sp_array_constructor_hook(void *) 284cdf0e10cSrcweir { 285cdf0e10cSrcweir } 286cdf0e10cSrcweir 287cdf0e10cSrcweir void sp_array_destructor_hook(void *) 288cdf0e10cSrcweir { 289cdf0e10cSrcweir } 290cdf0e10cSrcweir 291cdf0e10cSrcweir } // namespace boost 292cdf0e10cSrcweir 293cdf0e10cSrcweir #endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS) 294