2 Copyright (C) 2009 Paul Davis
3 From an idea by Carl Hetherington.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "libpbd-config.h"
32 #include <glibmm/thread.h>
33 #include <boost/shared_ptr.hpp>
35 #include "pbd/stacktrace.h"
40 std::ostream
& print (std::ostream
& str
) const;
47 std::ostream
& operator<< (std::ostream
& str
, const Backtrace
& bt
) { return bt
.print (str
); }
50 Backtrace::Backtrace()
53 size
= ::backtrace (trace
, 200);
58 Backtrace::print (std::ostream
& str
) const
65 strings
= ::backtrace_symbols (trace
, size
);
68 for (i
= 3; i
< 5+18 && i
< size
; i
++) {
69 str
<< strings
[i
] << std::endl
;
83 BTPair (Backtrace
* bt
) : ref (bt
), rel (0) {}
88 std::ostream
& operator<<(std::ostream
& str
, const BTPair
& btp
) {
89 str
<< "*********************************************\n";
90 if (btp
.ref
) str
<< *btp
.ref
<< std::endl
;
92 if (btp
.rel
) str
<< *btp
.rel
<< std::endl
;
97 Backtrace
* constructor
;
98 Backtrace
* destructor
;
100 SPDebug (Backtrace
* c
) : constructor (c
), destructor (0) {}
107 std::ostream
& operator<< (std::ostream
& str
, const SPDebug
& spd
)
109 str
<< "Constructor :" << std::endl
;
110 if (spd
.constructor
) {
111 str
<< *spd
.constructor
<< std::endl
;
117 typedef std::multimap
<void const*,SPDebug
*> PointerMap
;
118 typedef std::map
<void const*,const char*> IPointerMap
;
123 IPointerMap interesting_pointers
;
125 static Glib::StaticMutex the_lock
;
128 is_interesting_object (void const* ptr
)
134 return interesting_pointers
.find (ptr
) != interesting_pointers
.end();
137 /* ------------------------------- */
139 static bool debug_out
= false;
142 boost_debug_shared_ptr_show_live_debugging (bool yn
)
148 boost_debug_shared_ptr_mark_interesting (void* ptr
, const char* type
)
150 Glib::Mutex::Lock
guard (the_lock
);
151 pair
<void*,const char*> newpair (ptr
, type
);
152 interesting_pointers
.insert (newpair
);
154 cerr
<< "Interesting object @ " << ptr
<< " of type " << type
<< endl
;
159 boost_debug_shared_ptr_operator_equals (void const *sp
, void const *old_obj
, int old_use_count
, void const *obj
, int new_use_count
)
161 if (old_obj
== 0 && obj
== 0) {
165 Glib::Mutex::Lock
guard (the_lock
);
167 if (is_interesting_object (old_obj
) || is_interesting_object (obj
)) {
169 cerr
<< "ASSIGN SWAPS " << old_obj
<< " & " << obj
<< endl
;
173 if (is_interesting_object (old_obj
)) {
175 cerr
<< "\tlost old sp @ " << sp
<< " for " << old_obj
<< " UC = " << old_use_count
<< " now for " << obj
<< " UC = " << new_use_count
176 << " (total sp's = " << sptrs
.size() << ')' << endl
;
178 PointerMap::iterator x
= sptrs
.find (sp
);
180 if (x
!= sptrs
.end()) {
183 cerr
<< "\tRemoved (by assigment) sp for " << old_obj
<< " @ " << sp
<< " UC = " << old_use_count
<< " (total sp's = " << sptrs
.size() << ')' << endl
;
188 if (is_interesting_object (obj
)) {
190 pair
<void const*, SPDebug
*> newpair
;
193 newpair
.second
= new SPDebug (new Backtrace());
195 sptrs
.insert (newpair
);
198 cerr
<< "assignment created sp for " << obj
<< " @ " << sp
<< " used to point to " << old_obj
<< " UC = " << old_use_count
199 << " UC = " << new_use_count
200 << " (total sp's = " << sptrs
.size() << ')' << endl
;
201 cerr
<< *newpair
.second
<< endl
;
207 boost_debug_shared_ptr_reset (void const *sp
, void const *old_obj
, int old_use_count
, void const *obj
, int new_use_count
)
209 if (old_obj
== 0 && obj
== 0) {
213 Glib::Mutex::Lock
guard (the_lock
);
215 if (is_interesting_object (old_obj
) || is_interesting_object (obj
)) {
217 cerr
<< "RESET SWAPS " << old_obj
<< " & " << obj
<< endl
;
221 if (is_interesting_object (old_obj
)) {
223 cerr
<< "\tlost old sp @ " << sp
<< " for " << old_obj
<< " UC = " << old_use_count
<< " now for " << obj
<< " UC = " << new_use_count
224 << " (total sp's = " << sptrs
.size() << ')' << endl
;
226 PointerMap::iterator x
= sptrs
.find (sp
);
228 if (x
!= sptrs
.end()) {
231 cerr
<< "\tRemoved (by reset) sp for " << old_obj
<< " @ " << sp
<< " UC = " << old_use_count
<< " (total sp's = " << sptrs
.size() << ')' << endl
;
236 if (is_interesting_object (obj
)) {
238 pair
<void const*, SPDebug
*> newpair
;
241 newpair
.second
= new SPDebug (new Backtrace());
243 sptrs
.insert (newpair
);
246 cerr
<< "reset created sp for " << obj
<< " @ " << sp
<< " used to point to " << old_obj
<< " UC = " << old_use_count
247 << " UC = " << new_use_count
248 << " (total sp's = " << sptrs
.size() << ')' << endl
;
249 cerr
<< *newpair
.second
<< endl
;
255 boost_debug_shared_ptr_destructor (void const *sp
, void const *obj
, int use_count
)
257 Glib::Mutex::Lock
guard (the_lock
);
258 PointerMap::iterator x
= sptrs
.find (sp
);
260 if (x
!= sptrs
.end()) {
263 cerr
<< "Removed sp for " << obj
<< " @ " << sp
<< " UC = " << use_count
<< " (total sp's = " << sptrs
.size() << ')' << endl
;
269 boost_debug_shared_ptr_constructor (void const *sp
, void const *obj
, int use_count
)
271 if (is_interesting_object (obj
)) {
272 Glib::Mutex::Lock
guard (the_lock
);
273 pair
<void const*, SPDebug
*> newpair
;
276 newpair
.second
= new SPDebug (new Backtrace());
278 sptrs
.insert (newpair
);
280 cerr
<< "Stored constructor for " << obj
<< " @ " << sp
<< " UC = " << use_count
<< " (total sp's = " << sptrs
.size() << ')' << endl
;
281 cerr
<< *newpair
.second
<< endl
;
287 boost_debug_count_ptrs ()
289 Glib::Mutex::Lock
guard (the_lock
);
290 // cerr << "Tracking " << interesting_pointers.size() << " interesting objects with " << sptrs.size () << " shared ptrs\n";
294 boost_debug_list_ptrs ()
296 Glib::Mutex::Lock
guard (the_lock
);
299 cerr
<< "There are no dangling shared ptrs\n";
301 for (PointerMap::iterator x
= sptrs
.begin(); x
!= sptrs
.end(); ++x
) {
302 cerr
<< "Shared ptr @ " << x
->first
<< " history: "
311 void sp_scalar_constructor_hook( void * object
, std::size_t size
, void * pn
)
315 void sp_scalar_destructor_hook( void * object
, std::size_t size
, void * pn
)
319 void sp_counter_ref_hook (void* pn
, long use_count
)
323 void sp_counter_release_hook (void* pn
, long use_count
)
327 void sp_array_constructor_hook(void * p
)
331 void sp_array_destructor_hook(void * p
)
335 void sp_scalar_constructor_hook(void * p
)
339 void sp_scalar_destructor_hook(void * p
)