diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2009-11-23 17:33:39 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2009-11-23 17:33:39 +0000 |
commit | 5cfeaf410212c5bc104050820d1fb255b7a471b9 (patch) | |
tree | 8e53710118bff0a60df0fc6e9b878db755407265 /libs | |
parent | f8aaa397320d119b6ede6ea5fe3315c22e9786bf (diff) |
boost shared pointer debugging, from an idea by carl hetherington
git-svn-id: svn://localhost/ardour2/branches/3.0@6155 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r-- | libs/pbd/boost_debug.cc | 292 | ||||
-rw-r--r-- | libs/pbd/pbd/boost_debug.h | 29 | ||||
-rw-r--r-- | libs/pbd/wscript | 1 |
3 files changed, 322 insertions, 0 deletions
diff --git a/libs/pbd/boost_debug.cc b/libs/pbd/boost_debug.cc new file mode 100644 index 0000000000..eea0fc45e0 --- /dev/null +++ b/libs/pbd/boost_debug.cc @@ -0,0 +1,292 @@ +/* + Copyright (C) 2009 Paul Davis + From an idea by Carl Hetherington. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <stdlib.h> +#include <iostream> +#include <map> +#include <set> +#include <list> +#include <glibmm/thread.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); + 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; + size = ::backtrace (trace, 200); +} + +std::ostream& +Backtrace::print (std::ostream& str) const +{ + char **strings; + size_t i; + + if (size) { + strings = ::backtrace_symbols (trace, size); + + if (strings) { + for (i = 5; i < 5+12; i++) { + str << strings[i] << std::endl; + } + free (strings); + } + } + + return str; +} + +#else + +Backtrace::Backtrace(int addsub, int uc, void const* sp) { + _addsub = addsub; + _pn = pn; + size = 0; + _use_count = uc; +} + +std::ostream& +Backtrace::print (std::ostream& str) const +{ + return str << "No shared ptr debugging available on this platform\n"; +} + +#endif + +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; + +static TraceMap traces; +static PointerMap interesting_pointers; +static PointerSet interesting_counters; +static Glib::StaticMutex the_lock; + +using namespace std; + +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 bool +is_interesting_object (void const* ptr) +{ + if (ptr == 0) { + return false; + } + + return interesting_pointers.find (ptr) != interesting_pointers.end(); +} + +/* ------------------------------- */ + +void +boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type) +{ + Glib::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; +} + +void +boost_debug_shared_ptr_show (ostream& str, void* ptr) +{ + Glib::Mutex::Lock guard (the_lock); + pair<TraceMap::iterator,TraceMap::iterator> range; + + range = traces.equal_range (ptr); + + if (range.first == traces.end()) { + str << "No shared_ptr debugging information found for " << ptr << endl; + return; + } + + 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; + } + str << "\n**********************************************\n" + << "Back trace for " << op << " on " << ptr << " w/use_count = " << (*x)->use_count() << endl; + str << **x; + } + } +} + +namespace boost { + +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()); + + } +} + +void sp_scalar_destructor_hook( void * object, std::size_t size, void * pn ) +{ + 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()); + } + + Glib::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 (use_count == 1) { + traces.erase (range.first, range.second); + } + } + + if (use_count == 1) { + // PointerMap::iterator p = interesting_pointers.find (object); + + //if (p != interesting_pointers.end()) { + // interesting_pointers.erase (p); + //} + } +} + +void sp_counter_ref_hook (void* pn, long 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); + } +} +void sp_counter_release_hook (void* pn, long use_count) +{ + 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); + } +} + +void sp_array_constructor_hook(void * p) +{ +} + +void sp_array_destructor_hook(void * p) +{ +} + +void sp_scalar_constructor_hook(void * p) +{ +} + +void sp_scalar_destructor_hook(void * p) +{ +} + +} diff --git a/libs/pbd/pbd/boost_debug.h b/libs/pbd/pbd/boost_debug.h new file mode 100644 index 0000000000..513bf2512d --- /dev/null +++ b/libs/pbd/pbd/boost_debug.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2009 Paul Davis + From an idea by Carl Hetherington. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __pbd_boost_debug_h__ +#define __pbd_boost_debug_h__ + +#include <ostream> + +void boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type); +void boost_debug_shared_ptr_show (std::ostream& str, void* ptr); + +#endif /* __pbd_boost_debug_h__ */ diff --git a/libs/pbd/wscript b/libs/pbd/wscript index 5ecaf69643..122f38da79 100644 --- a/libs/pbd/wscript +++ b/libs/pbd/wscript @@ -53,6 +53,7 @@ def build(bld): obj.source = ''' basename.cc base_ui.cc + boost_debug.cc command.cc convert.cc controllable.cc |