4 // Copyright (c) 2002, 2003 Peter Dimov
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)
11 #if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
13 #include <boost/assert.hpp>
14 #include <boost/shared_ptr.hpp>
15 #include <boost/detail/lightweight_mutex.hpp>
21 typedef std::map
< void const *, std::pair
<void *, size_t> > map_type
;
23 static map_type
& get_map()
29 typedef boost::detail::lightweight_mutex mutex_type
;
31 static mutex_type
& get_mutex()
37 static void * init_mutex_before_main
= &get_mutex();
45 boost::detail::sp_counted_base
* pi
;
49 struct shared_ptr_layout
56 // assume 4 byte alignment for pointers when scanning
57 size_t const pointer_align
= 4;
59 typedef std::map
<void const *, long> map2_type
;
61 static void scan_and_count(void const * area
, size_t size
, map_type
const & m
, map2_type
& m2
)
63 unsigned char const * p
= static_cast<unsigned char const *>(area
);
65 for(size_t n
= 0; n
+ sizeof(shared_ptr_layout
) <= size
; p
+= pointer_align
, n
+= pointer_align
)
67 shared_ptr_layout
const * q
= reinterpret_cast<shared_ptr_layout
const *>(p
);
69 if(q
->pn
.id
== boost::detail::shared_count_id
&& q
->pn
.pi
!= 0 && m
.count(q
->pn
.pi
) != 0)
76 typedef std::deque
<void const *> open_type
;
78 static void scan_and_mark(void const * area
, size_t size
, map2_type
& m2
, open_type
& open
)
80 unsigned char const * p
= static_cast<unsigned char const *>(area
);
82 for(size_t n
= 0; n
+ sizeof(shared_ptr_layout
) <= size
; p
+= pointer_align
, n
+= pointer_align
)
84 shared_ptr_layout
const * q
= reinterpret_cast<shared_ptr_layout
const *>(p
);
86 if(q
->pn
.id
== boost::detail::shared_count_id
&& q
->pn
.pi
!= 0 && m2
.count(q
->pn
.pi
) != 0)
88 open
.push_back(q
->pn
.pi
);
94 static void find_unreachable_objects_impl(map_type
const & m
, map2_type
& m2
)
96 // scan objects for shared_ptr members, compute internal counts
99 std::cout
<< "... " << m
.size() << " objects in m.\n";
101 for(map_type::const_iterator i
= m
.begin(); i
!= m
.end(); ++i
)
103 boost::detail::sp_counted_base
const * p
= static_cast<boost::detail::sp_counted_base
const *>(i
->first
);
105 BOOST_ASSERT(p
->use_count() != 0); // there should be no inactive counts in the map
109 scan_and_count(i
->second
.first
, i
->second
.second
, m
, m2
);
112 std::cout
<< "... " << m2
.size() << " objects in m2.\n";
115 // mark reachable objects
120 for(map2_type::iterator i
= m2
.begin(); i
!= m2
.end(); ++i
)
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
);
126 std::cout
<< "... " << open
.size() << " objects in open.\n";
128 for(open_type::iterator j
= open
.begin(); j
!= open
.end(); ++j
)
135 void const * p
= open
.front();
138 map_type::const_iterator i
= m
.find(p
);
139 BOOST_ASSERT(i
!= m
.end());
141 scan_and_mark(i
->second
.first
, i
->second
.second
, m2
, open
);
145 // m2 now contains the unreachable objects
148 std::size_t find_unreachable_objects(bool report
)
152 #ifdef BOOST_HAS_THREADS
154 // This will work without the #ifdef, but some compilers warn
155 // that lock is not referenced
157 mutex_type::scoped_lock
lock(get_mutex());
161 map_type
const & m
= get_map();
163 find_unreachable_objects_impl(m
, m2
);
167 for(map2_type::iterator j
= m2
.begin(); j
!= m2
.end(); ++j
)
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";
178 typedef std::deque
< boost::shared_ptr
<X
> > free_list_type
;
180 static void scan_and_free(void * area
, size_t size
, map2_type
const & m2
, free_list_type
& free
)
182 unsigned char * p
= static_cast<unsigned char *>(area
);
184 for(size_t n
= 0; n
+ sizeof(shared_ptr_layout
) <= size
; p
+= pointer_align
, n
+= pointer_align
)
186 shared_ptr_layout
* q
= reinterpret_cast<shared_ptr_layout
*>(p
);
188 if(q
->pn
.id
== boost::detail::shared_count_id
&& q
->pn
.pi
!= 0 && m2
.count(q
->pn
.pi
) != 0 && q
->px
!= 0)
190 boost::shared_ptr
<X
> * ppx
= reinterpret_cast< boost::shared_ptr
<X
> * >(p
);
191 free
.push_back(*ppx
);
197 void free_unreachable_objects()
204 #ifdef BOOST_HAS_THREADS
206 mutex_type::scoped_lock
lock(get_mutex());
210 map_type
const & m
= get_map();
212 find_unreachable_objects_impl(m
, m2
);
214 for(map2_type::iterator j
= m2
.begin(); j
!= m2
.end(); ++j
)
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
);
222 std::cout
<< "... about to free " << free
.size() << " objects.\n";
230 void sp_scalar_constructor_hook(void *)
234 void sp_scalar_constructor_hook(void * px
, std::size_t size
, void * pn
)
236 #ifdef BOOST_HAS_THREADS
238 mutex_type::scoped_lock
lock(get_mutex());
242 get_map()[pn
] = std::make_pair(px
, size
);
245 void sp_scalar_destructor_hook(void *)
249 void sp_scalar_destructor_hook(void *, std::size_t, void * pn
)
251 #ifdef BOOST_HAS_THREADS
253 mutex_type::scoped_lock
lock(get_mutex());
260 void sp_array_constructor_hook(void *)
264 void sp_array_destructor_hook(void *)
270 #endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)