/*
- Copyright (C) 2009 Paul Davis
+ Copyright (C) 2009 Paul Davis
From an idea by Carl Hetherington.
This program is free software; you can redistribute it and/or modify
#include <map>
#include <set>
#include <vector>
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
#include <boost/shared_ptr.hpp>
#include "pbd/stacktrace.h"
+#include "pbd/boost_debug.h"
class Backtrace {
public:
std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
-Backtrace::Backtrace()
-{
+Backtrace::Backtrace()
+{
#ifdef HAVE_EXECINFO
size = ::backtrace (trace, 200);
#endif
if (size) {
#ifdef HAVE_EXECINFO
strings = ::backtrace_symbols (trace, size);
-#endif
+#endif
if (strings) {
- for (i = 5; i < 5+18 && i < size; i++) {
+ for (i = 3; i < 5+18 && i < size; i++) {
str << strings[i] << std::endl;
}
free (strings);
return str;
}
-struct BTPair {
+struct BTPair {
Backtrace* ref;
Backtrace* rel;
return str;
}
-struct SPDebug {
+struct SPDebug {
Backtrace* constructor;
Backtrace* destructor;
-
+
SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
~SPDebug () {
delete constructor;
using namespace std;
-PointerMap sptrs;
-IPointerMap interesting_pointers;
+static PointerMap* _sptrs;
+PointerMap& sptrs() {
+ if (_sptrs == 0) {
+ _sptrs = new PointerMap;
+ }
+ return *_sptrs;
+}
+
+static IPointerMap* _interesting_pointers;
+IPointerMap& interesting_pointers() {
+ if (_interesting_pointers == 0) {
+ _interesting_pointers = new IPointerMap;
+ }
+ return *_interesting_pointers;
+}
+
+static Glib::Threads::Mutex* _the_lock;
+static Glib::Threads::Mutex& the_lock() {
+ if (_the_lock == 0) {
+ _the_lock = new Glib::Threads::Mutex;
+ }
+ return *_the_lock;
+}
-static Glib::StaticMutex the_lock;
static bool
is_interesting_object (void const* ptr)
if (ptr == 0) {
return false;
}
-
- return interesting_pointers.find (ptr) != interesting_pointers.end();
+
+ return interesting_pointers().find (ptr) != interesting_pointers().end();
}
/* ------------------------------- */
+static bool debug_out = false;
+
+void
+boost_debug_shared_ptr_show_live_debugging (bool yn)
+{
+ debug_out = yn;
+}
+
void
boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
{
- Glib::Mutex::Lock guard (the_lock);
+ Glib::Threads::Mutex::Lock guard (the_lock());
pair<void*,const char*> newpair (ptr, type);
- interesting_pointers.insert (newpair);
- // cerr << "Interesting object @ " << ptr << " of type " << type << endl;
+ interesting_pointers().insert (newpair);
+ if (debug_out) {
+ cerr << "Interesting object @ " << ptr << " of type " << type << endl;
+ }
}
void
-boost_debug_shared_ptr_operator_equals (void const *sp, void const *obj, int)
+boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
{
+ if (old_obj == 0 && obj == 0) {
+ return;
+ }
+
+ Glib::Threads::Mutex::Lock guard (the_lock());
+
+ if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
+ if (debug_out) {
+ cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
+ }
+ }
+
+ if (is_interesting_object (old_obj)) {
+ if (debug_out) {
+ cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
+ << " (total sp's = " << sptrs().size() << ')' << endl;
+ }
+ PointerMap::iterator x = sptrs().find (sp);
+
+ if (x != sptrs().end()) {
+ sptrs().erase (x);
+ if (debug_out) {
+ cerr << "\tRemoved (by assignment) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
+ }
+ }
+ }
+
if (is_interesting_object (obj)) {
- cerr << "sp @ " << sp << " assigned\n";
+
+ pair<void const*, SPDebug*> newpair;
+
+ newpair.first = sp;
+ newpair.second = new SPDebug (new Backtrace());
+
+ sptrs().insert (newpair);
+
+ if (debug_out) {
+ cerr << "assignment created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
+ << " UC = " << new_use_count
+ << " (total sp's = " << sptrs().size() << ')' << endl;
+ cerr << *newpair.second << endl;
+ }
}
}
void
-boost_debug_shared_ptr_reset (void const *sp, void const *obj, int)
+boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
{
+ if (old_obj == 0 && obj == 0) {
+ return;
+ }
+
+ Glib::Threads::Mutex::Lock guard (the_lock());
+
+ if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
+ if (debug_out) {
+ cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
+ }
+ }
+
+ if (is_interesting_object (old_obj)) {
+ if (debug_out) {
+ cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
+ << " (total sp's = " << sptrs().size() << ')' << endl;
+ }
+ PointerMap::iterator x = sptrs().find (sp);
+
+ if (x != sptrs().end()) {
+ sptrs().erase (x);
+ if (debug_out) {
+ cerr << "\tRemoved (by reset) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
+ }
+ }
+ }
+
if (is_interesting_object (obj)) {
- cerr << "sp @ " << sp << " reset\n";
+
+ pair<void const*, SPDebug*> newpair;
+
+ newpair.first = sp;
+ newpair.second = new SPDebug (new Backtrace());
+
+ sptrs().insert (newpair);
+
+ if (debug_out) {
+ cerr << "reset created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
+ << " UC = " << new_use_count
+ << " (total sp's = " << sptrs().size() << ')' << endl;
+ cerr << *newpair.second << endl;
+ }
}
}
void
boost_debug_shared_ptr_destructor (void const *sp, void const *obj, int use_count)
{
- Glib::Mutex::Lock guard (the_lock);
- PointerMap::iterator x = sptrs.find (sp);
+ Glib::Threads::Mutex::Lock guard (the_lock());
+ PointerMap::iterator x = sptrs().find (sp);
- if (x != sptrs.end()) {
- sptrs.erase (x);
- // cerr << "Removed sp for " << obj << " @ " << sp << endl;
+ if (x != sptrs().end()) {
+ sptrs().erase (x);
+ if (debug_out) {
+ cerr << "Removed sp for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
+ }
}
}
boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
{
if (is_interesting_object (obj)) {
- Glib::Mutex::Lock guard (the_lock);
+ Glib::Threads::Mutex::Lock guard (the_lock());
pair<void const*, SPDebug*> newpair;
newpair.first = sp;
newpair.second = new SPDebug (new Backtrace());
- sptrs.insert (newpair);
- // cerr << "Stored constructor for " << obj << " @ " << sp << endl;
+ sptrs().insert (newpair);
+ if (debug_out) {
+ cerr << "Stored constructor for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
+ cerr << *newpair.second << endl;
+ }
}
}
+void
+boost_debug_count_ptrs ()
+{
+ Glib::Threads::Mutex::Lock guard (the_lock());
+ // cerr << "Tracking " << interesting_pointers().size() << " interesting objects with " << sptrs().size () << " shared ptrs\n";
+}
+
void
boost_debug_list_ptrs ()
{
- Glib::Mutex::Lock guard (the_lock);
+ Glib::Threads::Mutex::Lock guard (the_lock());
- if (sptrs.empty()) {
+ if (sptrs().empty()) {
cerr << "There are no dangling shared ptrs\n";
} else {
- for (PointerMap::iterator x = sptrs.begin(); x != sptrs.end(); ++x) {
+ for (PointerMap::iterator x = sptrs().begin(); x != sptrs().end(); ++x) {
cerr << "Shared ptr @ " << x->first << " history: "
<< *x->second
<< endl;
namespace boost {
-void sp_scalar_constructor_hook( void * object, std::size_t size, void * pn )
+void sp_scalar_constructor_hook( void *, std::size_t, void *)
{
}
-void sp_scalar_destructor_hook( void * object, std::size_t size, void * pn )
+void sp_scalar_destructor_hook( void *, std::size_t, void *)
{
}
-void sp_counter_ref_hook (void* pn, long use_count)
+void sp_counter_ref_hook (void* /*pn*/, long /* use count */)
{
}
-void sp_counter_release_hook (void* pn, long use_count)
+void sp_counter_release_hook (void* /*pn*/, long /*use_count*/)
{
}
-void sp_array_constructor_hook(void * p)
+void sp_array_constructor_hook(void *)
{
}
-void sp_array_destructor_hook(void * p)
+void sp_array_destructor_hook(void *)
{
}
-void sp_scalar_constructor_hook(void * p)
+void sp_scalar_constructor_hook(void *)
{
}
-void sp_scalar_destructor_hook(void * p)
+void sp_scalar_destructor_hook(void *)
{
}