Assorted doxygen fixes; no functional changes.
[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 static PointerMap* _sptrs;
123 PointerMap& sptrs() { 
124         if (_sptrs == 0) {
125                 _sptrs = new PointerMap;
126         }
127         return *_sptrs;
128 }
129
130 static IPointerMap* _interesting_pointers;
131 IPointerMap& interesting_pointers() { 
132         if (_interesting_pointers == 0) {
133                 _interesting_pointers = new IPointerMap;
134         }
135         return *_interesting_pointers;
136 }
137
138 static Glib::Mutex* _the_lock;
139 static Glib::Mutex& the_lock() {
140         if (_the_lock == 0) {
141                 _the_lock = new Glib::Mutex;
142         }
143         return *_the_lock;
144 }
145
146
147 static bool
148 is_interesting_object (void const* ptr)
149 {
150         if (ptr == 0) {
151                 return false;
152         }
153         
154         return interesting_pointers().find (ptr) != interesting_pointers().end();
155 }
156
157 /* ------------------------------- */
158
159 static bool debug_out = false;
160
161 void
162 boost_debug_shared_ptr_show_live_debugging (bool yn)
163 {
164         debug_out = yn;
165 }
166
167 void
168 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
169 {
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;
175         }
176 }
177
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)
180 {
181         if (old_obj == 0 && obj == 0) {
182                 return;
183         }
184
185         Glib::Mutex::Lock guard (the_lock());
186
187         if (is_interesting_object  (old_obj) || is_interesting_object (obj)) {
188                 if (debug_out) {
189                         cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
190                 }
191         }
192
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;                     
197                 }
198                 PointerMap::iterator x = sptrs().find (sp);
199                 
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;
204                         }
205                 }
206         }
207
208         if (is_interesting_object (obj)) {
209
210                 pair<void const*, SPDebug*> newpair;
211
212                 newpair.first = sp;
213                 newpair.second = new SPDebug (new Backtrace());
214
215                 sptrs().insert (newpair);
216                 
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;
222                 }
223         } 
224 }
225
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)
228 {
229         if (old_obj == 0 && obj == 0) {
230                 return;
231         }
232
233         Glib::Mutex::Lock guard (the_lock());
234
235         if (is_interesting_object  (old_obj) || is_interesting_object (obj)) {
236                 if (debug_out) {
237                         cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
238                 }
239         }
240
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;                     
245                 }
246                 PointerMap::iterator x = sptrs().find (sp);
247                 
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;
252                         }
253                 }
254         }
255
256         if (is_interesting_object (obj)) {
257
258                 pair<void const*, SPDebug*> newpair;
259
260                 newpair.first = sp;
261                 newpair.second = new SPDebug (new Backtrace());
262
263                 sptrs().insert (newpair);
264                 
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;
270                 }
271         } 
272 }
273
274 void
275 boost_debug_shared_ptr_destructor (void const *sp, void const *obj, int use_count)
276 {
277         Glib::Mutex::Lock guard (the_lock());
278         PointerMap::iterator x = sptrs().find (sp);
279
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;
284                 }
285         }
286 }
287
288 void
289 boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
290 {
291         if (is_interesting_object (obj)) {
292                 Glib::Mutex::Lock guard (the_lock());
293                 pair<void const*, SPDebug*> newpair;
294
295                 newpair.first = sp;
296                 newpair.second = new SPDebug (new Backtrace());
297
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;
302                 }
303         }
304 }
305
306 void
307 boost_debug_count_ptrs ()
308 {
309         Glib::Mutex::Lock guard (the_lock());
310         // cerr << "Tracking " << interesting_pointers().size() << " interesting objects with " << sptrs().size () << " shared ptrs\n";
311 }
312
313 void
314 boost_debug_list_ptrs ()
315 {
316         Glib::Mutex::Lock guard (the_lock());
317
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;
325                 }
326         }
327 }
328
329 namespace boost {
330
331 void sp_scalar_constructor_hook( void * object, std::size_t size, void * pn )
332 {
333 }
334
335 void sp_scalar_destructor_hook( void * object, std::size_t size, void * pn )
336 {
337 }
338
339 void sp_counter_ref_hook (void* pn, long use_count)
340 {
341 }
342
343 void sp_counter_release_hook (void* pn, long use_count) 
344 {
345 }
346
347 void sp_array_constructor_hook(void * p)
348 {
349 }
350
351 void sp_array_destructor_hook(void * p)
352 {
353 }
354
355 void sp_scalar_constructor_hook(void * p)
356 {
357 }
358
359 void sp_scalar_destructor_hook(void * p)
360 {
361 }
362
363 }