*/
+#include "libpbd-config.h"
+
+#ifdef HAVE_EXECINFO
+#include <execinfo.h>
+#endif
+
#include <stdlib.h>
#include <iostream>
#include <map>
#include <set>
-#include <list>
-#include <glibmm/thread.h>
+#include <vector>
+#include <glibmm/threads.h>
#include <boost/shared_ptr.hpp>
-#include "libpbd-config.h"
-
#include "pbd/stacktrace.h"
class Backtrace {
public:
- Backtrace (int addsub, int use_count, void const* pn);
+ Backtrace ();
std::ostream& print (std::ostream& str) const;
- int use_count() const { return _use_count; }
- void const* pn() const { return _pn; }
- int addsub() const { return _addsub; }
private:
- int _addsub;
- void const* _pn;
void* trace[200];
size_t size;
- int _use_count;
};
std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
-#ifdef HAVE_EXECINFO
-
-#include <execinfo.h>
-Backtrace::Backtrace(int addsub, int uc, void const* pn) {
- _addsub = addsub;
- _pn = pn;
- _use_count = uc;
+Backtrace::Backtrace()
+{
+#ifdef HAVE_EXECINFO
size = ::backtrace (trace, 200);
+#endif
}
std::ostream&
Backtrace::print (std::ostream& str) const
{
- char **strings;
+ char **strings = 0;
size_t i;
if (size) {
+#ifdef HAVE_EXECINFO
strings = ::backtrace_symbols (trace, size);
-
+#endif
if (strings) {
- for (i = 5; i < 5+12; i++) {
+ for (i = 3; i < 5+18 && i < size; i++) {
str << strings[i] << std::endl;
}
free (strings);
return str;
}
-#else
+struct BTPair {
+
+ Backtrace* ref;
+ Backtrace* rel;
-Backtrace::Backtrace(int addsub, int uc, void const* sp) {
- _addsub = addsub;
- _pn = pn;
- size = 0;
- _use_count = uc;
+ BTPair (Backtrace* bt) : ref (bt), rel (0) {}
+ ~BTPair () { }
+
+};
+
+std::ostream& operator<<(std::ostream& str, const BTPair& btp) {
+ str << "*********************************************\n";
+ if (btp.ref) str << *btp.ref << std::endl;
+ str << "Rel:\n";
+ if (btp.rel) str << *btp.rel << std::endl;
+ return str;
}
-std::ostream&
-Backtrace::print (std::ostream& str) const
+struct SPDebug {
+ Backtrace* constructor;
+ Backtrace* destructor;
+
+ SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
+ ~SPDebug () {
+ delete constructor;
+ delete destructor;
+ }
+};
+
+std::ostream& operator<< (std::ostream& str, const SPDebug& spd)
{
- return str << "No shared ptr debugging available on this platform\n";
+ str << "Constructor :" << std::endl;
+ if (spd.constructor) {
+ str << *spd.constructor << std::endl;
+ }
+
+ return str;
}
-#endif
+typedef std::multimap<void const*,SPDebug*> PointerMap;
+typedef std::map<void const*,const char*> IPointerMap;
-typedef std::list<Backtrace*> BacktraceList;
-typedef std::multimap<void const*,BacktraceList*> TraceMap;
-typedef std::map<void const*,const char*> PointerMap;
-typedef std::map<void const*,void const*> PointerSet;
+using namespace std;
-static TraceMap traces;
-static PointerMap interesting_pointers;
-static PointerSet interesting_counters;
-static Glib::StaticMutex the_lock;
+static PointerMap* _sptrs;
+PointerMap& sptrs() {
+ if (_sptrs == 0) {
+ _sptrs = new PointerMap;
+ }
+ return *_sptrs;
+}
-using namespace std;
+static IPointerMap* _interesting_pointers;
+IPointerMap& interesting_pointers() {
+ if (_interesting_pointers == 0) {
+ _interesting_pointers = new IPointerMap;
+ }
+ return *_interesting_pointers;
+}
-static void
-trace_it (int addsub, void const* pn, void const* object, int use_count)
-{
- Glib::Mutex::Lock guard (the_lock);
- Backtrace* bt = new Backtrace (addsub, use_count, pn);
- TraceMap::iterator i = traces.find (const_cast<void*>(object));
-
- if (i == traces.end()) {
- pair<void const *,BacktraceList*> newpair;
- newpair.first = object;
- newpair.second = new BacktraceList;
- newpair.second->push_back (bt);
- traces.insert (newpair);
- cerr << "Start tracelist for " << object << endl;
- } else {
- i->second->push_back (bt);
- cerr << "Extend tracelist for " << object << endl;
- }
+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 bool
is_interesting_object (void const* ptr)
{
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 << "New interesting pointer: " << ptr << " type = " << type << endl;
- for (PointerMap::iterator i = interesting_pointers.begin(); i != interesting_pointers.end(); ++i) {
- cerr << "IP : " << i->first << " type = " << i->second << endl;
- }
- cerr << "is interesting ? " << is_interesting_object (ptr) << endl;
+ interesting_pointers().insert (newpair);
+ if (debug_out) {
+ cerr << "Interesting object @ " << ptr << " of type " << type << endl;
+ }
}
void
-boost_debug_shared_ptr_show (ostream& str, void* ptr)
+boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
{
- Glib::Mutex::Lock guard (the_lock);
- pair<TraceMap::iterator,TraceMap::iterator> range;
+ if (old_obj == 0 && obj == 0) {
+ return;
+ }
- range = traces.equal_range (ptr);
+ Glib::Threads::Mutex::Lock guard (the_lock());
- if (range.first == traces.end()) {
- str << "No shared_ptr debugging information found for " << ptr << endl;
- return;
+ if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
+ if (debug_out) {
+ cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
+ }
}
- str << "\n\n--------------------------------------------------------\ninfo for " << ptr << endl;
-
- for (TraceMap::iterator i = range.first; i != range.second; ++i) {
- BacktraceList* bt;
- bt = i->second;
- for (BacktraceList::iterator x = bt->begin(); x != bt->end(); ++x) {
- const char* op;
- switch ((*x)->addsub()) {
- case 0:
- op = "CONST";
- break;
- case -1:
- op = "REL";
- break;
- case 1:
- op = "REF";
- break;
-
- case 2:
- op = "DESTROY";
- break;
+ 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;
}
- str << "\n**********************************************\n"
- << "Back trace for " << op << " on " << ptr << " w/use_count = " << (*x)->use_count() << endl;
- str << **x;
}
}
-}
-namespace boost {
+ if (is_interesting_object (obj)) {
-void sp_scalar_constructor_hook( void * object, std::size_t size, void * pn )
-{
- if (is_interesting_object (object)) {
- cerr << "Interesting counter @ " << pn << endl;
- pair<void const*,void const*> newpair (pn, object);
- interesting_counters.insert (newpair);
- trace_it (0, pn, object, ((boost::detail::sp_counted_base*)pn)->use_count());
+ 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 sp_scalar_destructor_hook( void * object, std::size_t size, void * pn )
+void
+boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
{
- pair<TraceMap::iterator,TraceMap::iterator> range;
- long use_count = ((boost::detail::sp_counted_base*)pn)->use_count();
-
- if (is_interesting_object (object)) {
- trace_it (2, pn, object, ((boost::detail::sp_counted_base*)pn)->use_count());
+ if (old_obj == 0 && obj == 0) {
+ return;
}
- Glib::Mutex::Lock guard (the_lock);
+ Glib::Threads::Mutex::Lock guard (the_lock());
- range = traces.equal_range (object);
-
- if (range.first != traces.end()) {
-
- for (TraceMap::iterator i = range.first; i != range.second; ++i) {
- BacktraceList* btlist;
-
- btlist = i->second;
- for (BacktraceList::iterator x = btlist->begin(); x != btlist->end(); ) {
- if ((*x)->pn() == pn) {
- delete *x;
- x = btlist->erase (x);
- } else {
- ++x;
- }
- }
-
- if (use_count == 1) {
- btlist->clear ();
- delete btlist;
- }
+ if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
+ if (debug_out) {
+ cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
}
+ }
- if (use_count == 1) {
- traces.erase (range.first, range.second);
+ 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 (use_count == 1) {
- // PointerMap::iterator p = interesting_pointers.find (object);
+
+ if (is_interesting_object (obj)) {
+
+ pair<void const*, SPDebug*> newpair;
+
+ newpair.first = sp;
+ newpair.second = new SPDebug (new Backtrace());
+
+ sptrs().insert (newpair);
- //if (p != interesting_pointers.end()) {
- // interesting_pointers.erase (p);
- //}
+ 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::Threads::Mutex::Lock guard (the_lock());
+ PointerMap::iterator x = sptrs().find (sp);
+
+ 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;
+ }
}
}
-void sp_counter_ref_hook (void* pn, long use_count)
+void
+boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
{
- PointerSet::iterator i = interesting_counters.find (pn);
- if (i != interesting_counters.end()) {
- //cerr << "UC for " << pn << " inc from " << use_count << endl;
- trace_it (1, pn, i->second, use_count);
+ if (is_interesting_object (obj)) {
+ Glib::Threads::Mutex::Lock guard (the_lock());
+ pair<void const*, SPDebug*> newpair;
+
+ newpair.first = sp;
+ newpair.second = new SPDebug (new Backtrace());
+
+ 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 sp_counter_release_hook (void* pn, long use_count)
+
+void
+boost_debug_count_ptrs ()
{
- PointerSet::iterator i = interesting_counters.find (pn);
- if (i != interesting_counters.end()) {
- cerr << "UC for " << pn << " dec from " << use_count << endl;
- trace_it (-1, pn, i->second, use_count);
+ 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::Threads::Mutex::Lock guard (the_lock());
+
+ if (sptrs().empty()) {
+ cerr << "There are no dangling shared ptrs\n";
+ } else {
+ for (PointerMap::iterator x = sptrs().begin(); x != sptrs().end(); ++x) {
+ cerr << "Shared ptr @ " << x->first << " history: "
+ << *x->second
+ << endl;
+ }
}
}
-void sp_array_constructor_hook(void * p)
+namespace boost {
+
+void sp_scalar_constructor_hook( void *, std::size_t, void *)
+{
+}
+
+void sp_scalar_destructor_hook( void *, std::size_t, void *)
+{
+}
+
+void sp_counter_ref_hook (void* /*pn*/, long /* use count */)
+{
+}
+
+void sp_counter_release_hook (void* /*pn*/, long /*use_count*/)
+{
+}
+
+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 *)
{
}