2 * Copyright (C) 2009-2018 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "libpbd-config.h"
31 #include <glibmm/threads.h>
32 #include <boost/shared_ptr.hpp>
34 #include "pbd/stacktrace.h"
35 #include "pbd/boost_debug.h"
40 std::ostream& print (std::ostream& str) const;
47 std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
49 Backtrace::Backtrace()
52 size = ::backtrace (trace, 200);
57 Backtrace::print (std::ostream& str) const
64 strings = ::backtrace_symbols (trace, size);
67 for (i = 3; i < 5+18 && i < size; i++) {
68 str << strings[i] << std::endl;
82 BTPair (Backtrace* bt) : ref (bt), rel (0) {}
86 std::ostream& operator<<(std::ostream& str, const BTPair& btp) {
87 str << "*********************************************\n";
88 if (btp.ref) str << *btp.ref << std::endl;
90 if (btp.rel) str << *btp.rel << std::endl;
95 Backtrace* constructor;
96 Backtrace* destructor;
98 SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
105 std::ostream& operator<< (std::ostream& str, const SPDebug& spd)
107 str << "Constructor :" << std::endl;
108 if (spd.constructor) {
109 str << *spd.constructor << std::endl;
115 typedef std::multimap<volatile void const*,SPDebug*> PointerMap;
116 typedef std::map<volatile void const*,const char*> IPointerMap;
120 static PointerMap* _sptrs;
124 _sptrs = new PointerMap;
129 static IPointerMap* _interesting_pointers;
130 IPointerMap& interesting_pointers()
132 if (_interesting_pointers == 0) {
133 _interesting_pointers = new IPointerMap;
135 return *_interesting_pointers;
138 static Glib::Threads::Mutex* _the_lock;
139 static Glib::Threads::Mutex& the_lock()
141 if (_the_lock == 0) {
142 _the_lock = new Glib::Threads::Mutex;
149 is_interesting_object (volatile void const* ptr)
155 return interesting_pointers().find (ptr) != interesting_pointers().end();
158 /* ------------------------------- */
160 static bool debug_out = false;
163 boost_debug_shared_ptr_show_live_debugging (bool yn)
169 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
171 Glib::Threads::Mutex::Lock guard (the_lock());
172 pair<void*,const char*> newpair (ptr, type);
173 interesting_pointers().insert (newpair);
175 cerr << "Interesting object @ " << ptr << " of type " << type << endl;
180 boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
182 if (old_obj == 0 && obj == 0) {
186 Glib::Threads::Mutex::Lock guard (the_lock());
188 if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
190 cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
194 if (is_interesting_object (old_obj)) {
196 cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
197 << " (total sp's = " << sptrs().size() << ')' << endl;
199 PointerMap::iterator x = sptrs().find (sp);
201 if (x != sptrs().end()) {
204 cerr << "\tRemoved (by assignment) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
209 if (is_interesting_object (obj)) {
211 pair<void const*, SPDebug*> newpair;
214 newpair.second = new SPDebug (new Backtrace());
216 sptrs().insert (newpair);
219 cerr << "assignment created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
220 << " UC = " << new_use_count
221 << " (total sp's = " << sptrs().size() << ')' << endl;
222 cerr << *newpair.second << endl;
228 boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
230 if (old_obj == 0 && obj == 0) {
234 Glib::Threads::Mutex::Lock guard (the_lock());
236 if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
238 cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
242 if (is_interesting_object (old_obj)) {
244 cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
245 << " (total sp's = " << sptrs().size() << ')' << endl;
247 PointerMap::iterator x = sptrs().find (sp);
249 if (x != sptrs().end()) {
252 cerr << "\tRemoved (by reset) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
257 if (is_interesting_object (obj)) {
259 pair<void const*, SPDebug*> newpair;
262 newpair.second = new SPDebug (new Backtrace());
264 sptrs().insert (newpair);
267 cerr << "reset created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
268 << " UC = " << new_use_count
269 << " (total sp's = " << sptrs().size() << ')' << endl;
270 cerr << *newpair.second << endl;
276 boost_debug_shared_ptr_destructor (void const *sp, volatile void const *obj, int use_count)
278 Glib::Threads::Mutex::Lock guard (the_lock());
279 PointerMap::iterator x = sptrs().find (sp);
281 if (x != sptrs().end()) {
284 cerr << "Removed sp for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
290 boost_debug_shared_ptr_constructor (void const *sp, volatile void const *obj, int use_count)
292 if (is_interesting_object (obj)) {
293 Glib::Threads::Mutex::Lock guard (the_lock());
294 pair<void const*, SPDebug*> newpair;
297 newpair.second = new SPDebug (new Backtrace());
299 sptrs().insert (newpair);
301 cerr << "Stored constructor for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
302 cerr << *newpair.second << endl;
308 boost_debug_count_ptrs ()
310 Glib::Threads::Mutex::Lock guard (the_lock());
311 // cerr << "Tracking " << interesting_pointers().size() << " interesting objects with " << sptrs().size () << " shared ptrs\n";
315 boost_debug_list_ptrs ()
317 Glib::Threads::Mutex::Lock guard (the_lock());
319 if (sptrs().empty()) {
320 cerr << "There are no dangling shared ptrs\n";
322 for (PointerMap::iterator x = sptrs().begin(); x != sptrs().end(); ++x) {
323 cerr << "Shared ptr @ " << x->first << " history: "
332 void sp_scalar_constructor_hook( void *, std::size_t, void *)
336 void sp_scalar_destructor_hook( void *, std::size_t, void *)
340 void sp_counter_ref_hook (void* /*pn*/, long /* use count */)
344 void sp_counter_release_hook (void* /*pn*/, long /*use_count*/)
348 void sp_array_constructor_hook(void *)
352 void sp_array_destructor_hook(void *)
356 void sp_scalar_constructor_hook(void *)
360 void sp_scalar_destructor_hook(void *)