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