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
get_map()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
get_mutex()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
scan_and_count(void const * area,size_t size,map_type const & m,map2_type & m2)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
scan_and_mark(void const * area,size_t size,map2_type & m2,open_type & open)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
find_unreachable_objects_impl(map_type const & m,map2_type & m2)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
find_unreachable_objects(bool report)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
scan_and_free(void * area,size_t size,map2_type const & m2,free_list_type & free)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
free_unreachable_objects()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
sp_scalar_constructor_hook(void *)253 void sp_scalar_constructor_hook(void *)
254 {
255 }
256
sp_scalar_constructor_hook(void * px,std::size_t size,void * pn)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
sp_scalar_destructor_hook(void *)268 void sp_scalar_destructor_hook(void *)
269 {
270 }
271
sp_scalar_destructor_hook(void *,std::size_t,void * pn)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
sp_array_constructor_hook(void *)283 void sp_array_constructor_hook(void *)
284 {
285 }
286
sp_array_destructor_hook(void *)287 void sp_array_destructor_hook(void *)
288 {
289 }
290
291 } // namespace boost
292
293 #endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
294