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