remove theme-specific names from RC.in files, substitute them during build
[ardour2.git] / libs / pbd / boost_debug.cc
blob9d307f64af7ab3fdb9d7a36765f7390e3e1c9d18
1 /*
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"
23 #ifdef HAVE_EXECINFO
24 #include <execinfo.h>
25 #endif
27 #include <stdlib.h>
28 #include <iostream>
29 #include <map>
30 #include <set>
31 #include <vector>
32 #include <glibmm/thread.h>
33 #include <boost/shared_ptr.hpp>
35 #include "pbd/stacktrace.h"
37 class Backtrace {
38 public:
39 Backtrace ();
40 std::ostream& print (std::ostream& str) const;
42 private:
43 void* trace[200];
44 size_t size;
47 std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
50 Backtrace::Backtrace()
52 #ifdef HAVE_EXECINFO
53 size = ::backtrace (trace, 200);
54 #endif
57 std::ostream&
58 Backtrace::print (std::ostream& str) const
60 char **strings = 0;
61 size_t i;
63 if (size) {
64 #ifdef HAVE_EXECINFO
65 strings = ::backtrace_symbols (trace, size);
66 #endif
67 if (strings) {
68 for (i = 3; i < 5+18 && i < size; i++) {
69 str << strings[i] << std::endl;
71 free (strings);
75 return str;
78 struct BTPair {
80 Backtrace* ref;
81 Backtrace* rel;
83 BTPair (Backtrace* bt) : ref (bt), rel (0) {}
84 ~BTPair () { }
88 std::ostream& operator<<(std::ostream& str, const BTPair& btp) {
89 str << "*********************************************\n";
90 if (btp.ref) str << *btp.ref << std::endl;
91 str << "Rel:\n";
92 if (btp.rel) str << *btp.rel << std::endl;
93 return str;
96 struct SPDebug {
97 Backtrace* constructor;
98 Backtrace* destructor;
100 SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
101 ~SPDebug () {
102 delete constructor;
103 delete destructor;
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;
114 return str;
117 typedef std::multimap<void const*,SPDebug*> PointerMap;
118 typedef std::map<void const*,const char*> IPointerMap;
120 using namespace std;
122 static PointerMap* _sptrs;
123 PointerMap& sptrs() {
124 if (_sptrs == 0) {
125 _sptrs = new PointerMap;
127 return *_sptrs;
130 static IPointerMap* _interesting_pointers;
131 IPointerMap& interesting_pointers() {
132 if (_interesting_pointers == 0) {
133 _interesting_pointers = new IPointerMap;
135 return *_interesting_pointers;
138 static Glib::Mutex* _the_lock;
139 static Glib::Mutex& the_lock() {
140 if (_the_lock == 0) {
141 _the_lock = new Glib::Mutex;
143 return *_the_lock;
147 static bool
148 is_interesting_object (void const* ptr)
150 if (ptr == 0) {
151 return false;
154 return interesting_pointers().find (ptr) != interesting_pointers().end();
157 /* ------------------------------- */
159 static bool debug_out = false;
161 void
162 boost_debug_shared_ptr_show_live_debugging (bool yn)
164 debug_out = yn;
167 void
168 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
170 Glib::Mutex::Lock guard (the_lock());
171 pair<void*,const char*> newpair (ptr, type);
172 interesting_pointers().insert (newpair);
173 if (debug_out) {
174 cerr << "Interesting object @ " << ptr << " of type " << type << endl;
178 void
179 boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
181 if (old_obj == 0 && obj == 0) {
182 return;
185 Glib::Mutex::Lock guard (the_lock());
187 if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
188 if (debug_out) {
189 cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
193 if (is_interesting_object (old_obj)) {
194 if (debug_out) {
195 cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
196 << " (total sp's = " << sptrs().size() << ')' << endl;
198 PointerMap::iterator x = sptrs().find (sp);
200 if (x != sptrs().end()) {
201 sptrs().erase (x);
202 if (debug_out) {
203 cerr << "\tRemoved (by assigment) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
208 if (is_interesting_object (obj)) {
210 pair<void const*, SPDebug*> newpair;
212 newpair.first = sp;
213 newpair.second = new SPDebug (new Backtrace());
215 sptrs().insert (newpair);
217 if (debug_out) {
218 cerr << "assignment created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
219 << " UC = " << new_use_count
220 << " (total sp's = " << sptrs().size() << ')' << endl;
221 cerr << *newpair.second << endl;
226 void
227 boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count, void const *obj, int new_use_count)
229 if (old_obj == 0 && obj == 0) {
230 return;
233 Glib::Mutex::Lock guard (the_lock());
235 if (is_interesting_object (old_obj) || is_interesting_object (obj)) {
236 if (debug_out) {
237 cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
241 if (is_interesting_object (old_obj)) {
242 if (debug_out) {
243 cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
244 << " (total sp's = " << sptrs().size() << ')' << endl;
246 PointerMap::iterator x = sptrs().find (sp);
248 if (x != sptrs().end()) {
249 sptrs().erase (x);
250 if (debug_out) {
251 cerr << "\tRemoved (by reset) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
256 if (is_interesting_object (obj)) {
258 pair<void const*, SPDebug*> newpair;
260 newpair.first = sp;
261 newpair.second = new SPDebug (new Backtrace());
263 sptrs().insert (newpair);
265 if (debug_out) {
266 cerr << "reset created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
267 << " UC = " << new_use_count
268 << " (total sp's = " << sptrs().size() << ')' << endl;
269 cerr << *newpair.second << endl;
274 void
275 boost_debug_shared_ptr_destructor (void const *sp, void const *obj, int use_count)
277 Glib::Mutex::Lock guard (the_lock());
278 PointerMap::iterator x = sptrs().find (sp);
280 if (x != sptrs().end()) {
281 sptrs().erase (x);
282 if (debug_out) {
283 cerr << "Removed sp for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
288 void
289 boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
291 if (is_interesting_object (obj)) {
292 Glib::Mutex::Lock guard (the_lock());
293 pair<void const*, SPDebug*> newpair;
295 newpair.first = sp;
296 newpair.second = new SPDebug (new Backtrace());
298 sptrs().insert (newpair);
299 if (debug_out) {
300 cerr << "Stored constructor for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
301 cerr << *newpair.second << endl;
306 void
307 boost_debug_count_ptrs ()
309 Glib::Mutex::Lock guard (the_lock());
310 // cerr << "Tracking " << interesting_pointers().size() << " interesting objects with " << sptrs().size () << " shared ptrs\n";
313 void
314 boost_debug_list_ptrs ()
316 Glib::Mutex::Lock guard (the_lock());
318 if (sptrs().empty()) {
319 cerr << "There are no dangling shared ptrs\n";
320 } else {
321 for (PointerMap::iterator x = sptrs().begin(); x != sptrs().end(); ++x) {
322 cerr << "Shared ptr @ " << x->first << " history: "
323 << *x->second
324 << endl;
329 namespace boost {
331 void sp_scalar_constructor_hook( void * object, std::size_t size, void * pn )
335 void sp_scalar_destructor_hook( void * object, std::size_t size, void * pn )
339 void sp_counter_ref_hook (void* pn, long use_count)
343 void sp_counter_release_hook (void* pn, long use_count)
347 void sp_array_constructor_hook(void * p)
351 void sp_array_destructor_hook(void * p)
355 void sp_scalar_constructor_hook(void * p)
359 void sp_scalar_destructor_hook(void * p)