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