blob: 379f8e9d820a7fa10d563de3a49c0dcd47eacdc6 [file] [log] [blame]
Jeff Thompsona28eed82013-08-22 16:21:10 -07001//
2// sp_collector.cpp
3//
4// Copyright (c) 2002, 2003 Peter Dimov
5//
6// Distributed under the Boost Software License, Version 1.0. (See
7// accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9//
10
11#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
12
13#include <boost/assert.hpp>
14#include <boost/shared_ptr.hpp>
15#include <boost/detail/lightweight_mutex.hpp>
16#include <cstdlib>
17#include <map>
18#include <deque>
19#include <iostream>
20
21typedef std::map< void const *, std::pair<void *, size_t> > map_type;
22
23static map_type & get_map()
24{
25 static map_type m;
26 return m;
27}
28
29typedef ndnboost::detail::lightweight_mutex mutex_type;
30
31static mutex_type & get_mutex()
32{
33 static mutex_type m;
34 return m;
35}
36
37static void * init_mutex_before_main = &get_mutex();
38
39namespace
40{
41 class X;
42
43 struct count_layout
44 {
45 ndnboost::detail::sp_counted_base * pi;
46 int id;
47 };
48
49 struct shared_ptr_layout
50 {
51 X * px;
52 count_layout pn;
53 };
54}
55
56// assume 4 byte alignment for pointers when scanning
57size_t const pointer_align = 4;
58
59typedef std::map<void const *, long> map2_type;
60
61static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2)
62{
63 unsigned char const * p = static_cast<unsigned char const *>(area);
64
65 for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
66 {
67 shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
68
69 if(q->pn.id == ndnboost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0)
70 {
71 ++m2[q->pn.pi];
72 }
73 }
74}
75
76typedef std::deque<void const *> open_type;
77
78static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
79{
80 unsigned char const * p = static_cast<unsigned char const *>(area);
81
82 for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
83 {
84 shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
85
86 if(q->pn.id == ndnboost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0)
87 {
88 open.push_back(q->pn.pi);
89 m2.erase(q->pn.pi);
90 }
91 }
92}
93
94static void find_unreachable_objects_impl(map_type const & m, map2_type & m2)
95{
96 // scan objects for shared_ptr members, compute internal counts
97
98 {
99 std::cout << "... " << m.size() << " objects in m.\n";
100
101 for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
102 {
103 ndnboost::detail::sp_counted_base const * p = static_cast<ndnboost::detail::sp_counted_base const *>(i->first);
104
105 BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map
106
107 m2[ i->first ];
108
109 scan_and_count(i->second.first, i->second.second, m, m2);
110 }
111
112 std::cout << "... " << m2.size() << " objects in m2.\n";
113 }
114
115 // mark reachable objects
116
117 {
118 open_type open;
119
120 for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
121 {
122 ndnboost::detail::sp_counted_base const * p = static_cast<ndnboost::detail::sp_counted_base const *>(i->first);
123 if(p->use_count() != i->second) open.push_back(p);
124 }
125
126 std::cout << "... " << open.size() << " objects in open.\n";
127
128 for(open_type::iterator j = open.begin(); j != open.end(); ++j)
129 {
130 m2.erase(*j);
131 }
132
133 while(!open.empty())
134 {
135 void const * p = open.front();
136 open.pop_front();
137
138 map_type::const_iterator i = m.find(p);
139 BOOST_ASSERT(i != m.end());
140
141 scan_and_mark(i->second.first, i->second.second, m2, open);
142 }
143 }
144
145 // m2 now contains the unreachable objects
146}
147
148std::size_t find_unreachable_objects(bool report)
149{
150 map2_type m2;
151
152#ifdef BOOST_HAS_THREADS
153
154 // This will work without the #ifdef, but some compilers warn
155 // that lock is not referenced
156
157 mutex_type::scoped_lock lock(get_mutex());
158
159#endif
160
161 map_type const & m = get_map();
162
163 find_unreachable_objects_impl(m, m2);
164
165 if(report)
166 {
167 for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
168 {
169 map_type::const_iterator i = m.find(j->first);
170 BOOST_ASSERT(i != m.end());
171 std::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
172 }
173 }
174
175 return m2.size();
176}
177
178typedef std::deque< ndnboost::shared_ptr<X> > free_list_type;
179
180static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free)
181{
182 unsigned char * p = static_cast<unsigned char *>(area);
183
184 for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
185 {
186 shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p);
187
188 if(q->pn.id == ndnboost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0)
189 {
190 ndnboost::shared_ptr<X> * ppx = reinterpret_cast< ndnboost::shared_ptr<X> * >(p);
191 free.push_back(*ppx);
192 ppx->reset();
193 }
194 }
195}
196
197void free_unreachable_objects()
198{
199 free_list_type free;
200
201 {
202 map2_type m2;
203
204#ifdef BOOST_HAS_THREADS
205
206 mutex_type::scoped_lock lock(get_mutex());
207
208#endif
209
210 map_type const & m = get_map();
211
212 find_unreachable_objects_impl(m, m2);
213
214 for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
215 {
216 map_type::const_iterator i = m.find(j->first);
217 BOOST_ASSERT(i != m.end());
218 scan_and_free(i->second.first, i->second.second, m2, free);
219 }
220 }
221
222 std::cout << "... about to free " << free.size() << " objects.\n";
223}
224
225// debug hooks
226
227namespace ndnboost
228{
229
230void sp_scalar_constructor_hook(void *)
231{
232}
233
234void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn)
235{
236#ifdef BOOST_HAS_THREADS
237
238 mutex_type::scoped_lock lock(get_mutex());
239
240#endif
241
242 get_map()[pn] = std::make_pair(px, size);
243}
244
245void sp_scalar_destructor_hook(void *)
246{
247}
248
249void sp_scalar_destructor_hook(void *, std::size_t, void * pn)
250{
251#ifdef BOOST_HAS_THREADS
252
253 mutex_type::scoped_lock lock(get_mutex());
254
255#endif
256
257 get_map().erase(pn);
258}
259
260void sp_array_constructor_hook(void *)
261{
262}
263
264void sp_array_destructor_hook(void *)
265{
266}
267
268} // namespace ndnboost
269
270#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)