]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / smart_ptr / extras / src / sp_collector.cpp
1 //
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
21 typedef std::map< void const *, std::pair<void *, size_t> > map_type;
22
23 static map_type & get_map()
24 {
25 static map_type m;
26 return m;
27 }
28
29 typedef boost::detail::lightweight_mutex mutex_type;
30
31 static mutex_type & get_mutex()
32 {
33 static mutex_type m;
34 return m;
35 }
36
37 static void * init_mutex_before_main = &get_mutex();
38
39 namespace
40 {
41 class X;
42
43 struct count_layout
44 {
45 boost::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
57 size_t const pointer_align = 4;
58
59 typedef std::map<void const *, long> map2_type;
60
61 static 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 == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0)
70 {
71 ++m2[q->pn.pi];
72 }
73 }
74 }
75
76 typedef std::deque<void const *> open_type;
77
78 static 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 == boost::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
94 static 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 boost::detail::sp_counted_base const * p = static_cast<boost::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 boost::detail::sp_counted_base const * p = static_cast<boost::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
148 std::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
178 typedef std::deque< boost::shared_ptr<X> > free_list_type;
179
180 static 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 == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0)
189 {
190 boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p);
191 free.push_back(*ppx);
192 ppx->reset();
193 }
194 }
195 }
196
197 void 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
227 namespace boost
228 {
229
230 void sp_scalar_constructor_hook(void *)
231 {
232 }
233
234 void 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
245 void sp_scalar_destructor_hook(void *)
246 {
247 }
248
249 void 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
260 void sp_array_constructor_hook(void *)
261 {
262 }
263
264 void sp_array_destructor_hook(void *)
265 {
266 }
267
268 } // namespace boost
269
270 #endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)