add EPA stuff from 2.X
[ardour.git] / libs / pbd / boost_debug.cc
1 /*
2     Copyright (C) 2009 Paul Davis 
3     From an idea by Carl Hetherington.
4
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.
9
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.
14
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.
18
19 */
20
21 #include "libpbd-config.h"
22
23 #ifdef HAVE_EXECINFO
24 #include <execinfo.h>
25 #endif
26
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>
34
35 #include "pbd/stacktrace.h"
36
37 class Backtrace {
38 public:
39     Backtrace ();
40     std::ostream& print (std::ostream& str) const;
41
42 private:
43     void* trace[200];
44     size_t size;
45 };
46
47 std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
48
49
50 Backtrace::Backtrace() 
51
52 #ifdef HAVE_EXECINFO
53         size = ::backtrace (trace, 200);
54 #endif
55 }
56
57 std::ostream&
58 Backtrace::print (std::ostream& str) const
59 {
60         char **strings = 0;
61         size_t i;
62
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;
70                         }
71                         free (strings);
72                 }
73         }
74
75         return str;
76 }
77
78 struct BTPair { 
79
80     Backtrace* ref;
81     Backtrace* rel;
82
83     BTPair (Backtrace* bt) : ref (bt), rel (0) {}
84     ~BTPair () { }
85
86 };
87
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;
94 }
95
96 struct SPDebug { 
97     Backtrace* constructor;
98     Backtrace* destructor;
99     
100     SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
101     ~SPDebug () {
102             delete constructor;
103             delete destructor;
104     }
105 };
106
107 std::ostream& operator<< (std::ostream& str, const SPDebug& spd)
108 {
109         str << "Constructor :" << std::endl;
110         if (spd.constructor) {
111                 str << *spd.constructor << std::endl;
112         }
113
114         return str;
115 }
116
117 typedef std::multimap<void const*,SPDebug*> PointerMap;
118 typedef std::map<void const*,const char*> IPointerMap;
119
120 using namespace std;
121
122 PointerMap sptrs;
123 IPointerMap interesting_pointers;
124
125 static Glib::StaticMutex the_lock;
126
127 static bool
128 is_interesting_object (void const* ptr)
129 {
130         if (ptr == 0) {
131                 return false;
132         }
133         
134         return interesting_pointers.find (ptr) != interesting_pointers.end();
135 }
136
137 /* ------------------------------- */
138
139 static bool debug_out = false;
140
141 void
142 boost_debug_shared_ptr_show_live_debugging (bool yn)
143 {
144         debug_out = yn;
145 }
146
147 void
148 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
149 {
150         Glib::Mutex::Lock guard (the_lock);
151         pair<void*,const char*> newpair (ptr, type);
152         interesting_pointers.insert (newpair);
153         if (debug_out) {
154                 cerr << "Interesting object @ " << ptr << " of type " << type << endl;
155         }
156 }
157
158 void
159 boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count,  void const *obj, int new_use_count)
160 {
161         if (old_obj == 0 && obj == 0) {
162                 return;
163         }
164
165         Glib::Mutex::Lock guard (the_lock);
166
167         if (is_interesting_object  (old_obj) || is_interesting_object (obj)) {
168                 if (debug_out) {
169                         cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
170                 }
171         }
172
173         if (is_interesting_object (old_obj)) {
174                 if (debug_out) {
175                         cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count 
176                              << " (total sp's = " << sptrs.size() << ')' << endl;                       
177                 }
178                 PointerMap::iterator x = sptrs.find (sp);
179                 
180                 if (x != sptrs.end()) {
181                         sptrs.erase (x);
182                         if (debug_out) {
183                                 cerr << "\tRemoved (by assigment) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs.size() << ')' << endl;
184                         }
185                 }
186         }
187
188         if (is_interesting_object (obj)) {
189
190                 pair<void const*, SPDebug*> newpair;
191
192                 newpair.first = sp;
193                 newpair.second = new SPDebug (new Backtrace());
194
195                 sptrs.insert (newpair);
196                 
197                 if (debug_out) {
198                         cerr << "assignment created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count 
199                              << " UC = " << new_use_count 
200                              << " (total sp's = " << sptrs.size() << ')' << endl;                       
201                         cerr << *newpair.second << endl;
202                 }
203         } 
204 }
205
206 void
207 boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count,  void const *obj, int new_use_count)
208 {
209         if (old_obj == 0 && obj == 0) {
210                 return;
211         }
212
213         Glib::Mutex::Lock guard (the_lock);
214
215         if (is_interesting_object  (old_obj) || is_interesting_object (obj)) {
216                 if (debug_out) {
217                         cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
218                 }
219         }
220
221         if (is_interesting_object (old_obj)) {
222                 if (debug_out) {
223                         cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count 
224                              << " (total sp's = " << sptrs.size() << ')' << endl;                       
225                 }
226                 PointerMap::iterator x = sptrs.find (sp);
227                 
228                 if (x != sptrs.end()) {
229                         sptrs.erase (x);
230                         if (debug_out) {
231                                 cerr << "\tRemoved (by reset) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs.size() << ')' << endl;
232                         }
233                 }
234         }
235
236         if (is_interesting_object (obj)) {
237
238                 pair<void const*, SPDebug*> newpair;
239
240                 newpair.first = sp;
241                 newpair.second = new SPDebug (new Backtrace());
242
243                 sptrs.insert (newpair);
244                 
245                 if (debug_out) {
246                         cerr << "reset created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count 
247                              << " UC = " << new_use_count 
248                              << " (total sp's = " << sptrs.size() << ')' << endl;                       
249                         cerr << *newpair.second << endl;
250                 }
251         } 
252 }
253
254 void
255 boost_debug_shared_ptr_destructor (void const *sp, void const *obj, int use_count)
256 {
257         Glib::Mutex::Lock guard (the_lock);
258         PointerMap::iterator x = sptrs.find (sp);
259
260         if (x != sptrs.end()) {
261                 sptrs.erase (x);
262                 if (debug_out) {
263                         cerr << "Removed sp for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs.size() << ')' << endl;
264                 }
265         }
266 }
267
268 void
269 boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
270 {
271         if (is_interesting_object (obj)) {
272                 Glib::Mutex::Lock guard (the_lock);
273                 pair<void const*, SPDebug*> newpair;
274
275                 newpair.first = sp;
276                 newpair.second = new SPDebug (new Backtrace());
277
278                 sptrs.insert (newpair);
279                 if (debug_out) {
280                         cerr << "Stored constructor for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs.size() << ')' << endl;
281                         cerr << *newpair.second << endl;
282                 }
283         }
284 }
285
286 void
287 boost_debug_count_ptrs ()
288 {
289         Glib::Mutex::Lock guard (the_lock);
290         // cerr << "Tracking " << interesting_pointers.size() << " interesting objects with " << sptrs.size () << " shared ptrs\n";
291 }
292
293 void
294 boost_debug_list_ptrs ()
295 {
296         Glib::Mutex::Lock guard (the_lock);
297
298         if (sptrs.empty()) {
299                 cerr << "There are no dangling shared ptrs\n";
300         } else {
301                 for (PointerMap::iterator x = sptrs.begin(); x != sptrs.end(); ++x) {
302                         cerr << "Shared ptr @ " << x->first << " history: "
303                              << *x->second
304                              << endl;
305                 }
306         }
307 }
308
309 namespace boost {
310
311 void sp_scalar_constructor_hook( void * object, std::size_t size, void * pn )
312 {
313 }
314
315 void sp_scalar_destructor_hook( void * object, std::size_t size, void * pn )
316 {
317 }
318
319 void sp_counter_ref_hook (void* pn, long use_count)
320 {
321 }
322
323 void sp_counter_release_hook (void* pn, long use_count) 
324 {
325 }
326
327 void sp_array_constructor_hook(void * p)
328 {
329 }
330
331 void sp_array_destructor_hook(void * p)
332 {
333 }
334
335 void sp_scalar_constructor_hook(void * p)
336 {
337 }
338
339 void sp_scalar_destructor_hook(void * p)
340 {
341 }
342
343 }