NO-OP: <tab> after <space> fixes in libs
[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/threads.h>
33 #include <boost/shared_ptr.hpp>
34
35 #include "pbd/stacktrace.h"
36 #include "pbd/boost_debug.h"
37
38 class Backtrace {
39 public:
40         Backtrace ();
41         std::ostream& print (std::ostream& str) const;
42
43 private:
44         void* trace[200];
45         size_t size;
46 };
47
48 std::ostream& operator<< (std::ostream& str, const Backtrace& bt) { return bt.print (str); }
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 std::ostream& operator<<(std::ostream& str, const BTPair& btp) {
88         str << "*********************************************\n";
89         if (btp.ref) str << *btp.ref << std::endl;
90         str << "Rel:\n";
91         if (btp.rel) str << *btp.rel << std::endl;
92         return str;
93 }
94
95 struct SPDebug {
96         Backtrace* constructor;
97         Backtrace* destructor;
98
99         SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
100         ~SPDebug () {
101                 delete constructor;
102                 delete destructor;
103         }
104 };
105
106 std::ostream& operator<< (std::ostream& str, const SPDebug& spd)
107 {
108         str << "Constructor :" << std::endl;
109         if (spd.constructor) {
110                 str << *spd.constructor << std::endl;
111         }
112
113         return str;
114 }
115
116 typedef std::multimap<volatile void const*,SPDebug*> PointerMap;
117 typedef std::map<volatile void const*,const char*> IPointerMap;
118
119 using namespace std;
120
121 static PointerMap* _sptrs;
122 PointerMap& sptrs()
123 {
124         if (_sptrs == 0) {
125                 _sptrs = new PointerMap;
126         }
127         return *_sptrs;
128 }
129
130 static IPointerMap* _interesting_pointers;
131 IPointerMap& interesting_pointers()
132 {
133         if (_interesting_pointers == 0) {
134                 _interesting_pointers = new IPointerMap;
135         }
136         return *_interesting_pointers;
137 }
138
139 static Glib::Threads::Mutex* _the_lock;
140 static Glib::Threads::Mutex& the_lock()
141 {
142         if (_the_lock == 0) {
143                 _the_lock = new Glib::Threads::Mutex;
144         }
145         return *_the_lock;
146 }
147
148
149 static bool
150 is_interesting_object (volatile void const* ptr)
151 {
152         if (ptr == 0) {
153                 return false;
154         }
155
156         return interesting_pointers().find (ptr) != interesting_pointers().end();
157 }
158
159 /* ------------------------------- */
160
161 static bool debug_out = false;
162
163 void
164 boost_debug_shared_ptr_show_live_debugging (bool yn)
165 {
166         debug_out = yn;
167 }
168
169 void
170 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
171 {
172         Glib::Threads::Mutex::Lock guard (the_lock());
173         pair<void*,const char*> newpair (ptr, type);
174         interesting_pointers().insert (newpair);
175         if (debug_out) {
176                 cerr << "Interesting object @ " << ptr << " of type " << type << endl;
177         }
178 }
179
180 void
181 boost_debug_shared_ptr_operator_equals (void const *sp, void const *old_obj, int old_use_count,  void const *obj, int new_use_count)
182 {
183         if (old_obj == 0 && obj == 0) {
184                 return;
185         }
186
187         Glib::Threads::Mutex::Lock guard (the_lock());
188
189         if (is_interesting_object  (old_obj) || is_interesting_object (obj)) {
190                 if (debug_out) {
191                         cerr << "ASSIGN SWAPS " << old_obj << " & " << obj << endl;
192                 }
193         }
194
195         if (is_interesting_object (old_obj)) {
196                 if (debug_out) {
197                         cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
198                              << " (total sp's = " << sptrs().size() << ')' << endl;
199                 }
200                 PointerMap::iterator x = sptrs().find (sp);
201
202                 if (x != sptrs().end()) {
203                         sptrs().erase (x);
204                         if (debug_out) {
205                                 cerr << "\tRemoved (by assignment) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
206                         }
207                 }
208         }
209
210         if (is_interesting_object (obj)) {
211
212                 pair<void const*, SPDebug*> newpair;
213
214                 newpair.first = sp;
215                 newpair.second = new SPDebug (new Backtrace());
216
217                 sptrs().insert (newpair);
218
219                 if (debug_out) {
220                         cerr << "assignment created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
221                              << " UC = " << new_use_count
222                              << " (total sp's = " << sptrs().size() << ')' << endl;
223                         cerr << *newpair.second << endl;
224                 }
225         }
226 }
227
228 void
229 boost_debug_shared_ptr_reset (void const *sp, void const *old_obj, int old_use_count,  void const *obj, int new_use_count)
230 {
231         if (old_obj == 0 && obj == 0) {
232                 return;
233         }
234
235         Glib::Threads::Mutex::Lock guard (the_lock());
236
237         if (is_interesting_object  (old_obj) || is_interesting_object (obj)) {
238                 if (debug_out) {
239                         cerr << "RESET SWAPS " << old_obj << " & " << obj << endl;
240                 }
241         }
242
243         if (is_interesting_object (old_obj)) {
244                 if (debug_out) {
245                         cerr << "\tlost old sp @ " << sp << " for " << old_obj << " UC = " << old_use_count << " now for " << obj << " UC = " << new_use_count
246                              << " (total sp's = " << sptrs().size() << ')' << endl;
247                 }
248                 PointerMap::iterator x = sptrs().find (sp);
249
250                 if (x != sptrs().end()) {
251                         sptrs().erase (x);
252                         if (debug_out) {
253                                 cerr << "\tRemoved (by reset) sp for " << old_obj << " @ " << sp << " UC = " << old_use_count << " (total sp's = " << sptrs().size() << ')' << endl;
254                         }
255                 }
256         }
257
258         if (is_interesting_object (obj)) {
259
260                 pair<void const*, SPDebug*> newpair;
261
262                 newpair.first = sp;
263                 newpair.second = new SPDebug (new Backtrace());
264
265                 sptrs().insert (newpair);
266
267                 if (debug_out) {
268                         cerr << "reset created sp for " << obj << " @ " << sp << " used to point to " << old_obj << " UC = " << old_use_count
269                              << " UC = " << new_use_count
270                              << " (total sp's = " << sptrs().size() << ')' << endl;
271                         cerr << *newpair.second << endl;
272                 }
273         }
274 }
275
276 void
277 boost_debug_shared_ptr_destructor (void const *sp, volatile void const *obj, int use_count)
278 {
279         Glib::Threads::Mutex::Lock guard (the_lock());
280         PointerMap::iterator x = sptrs().find (sp);
281
282         if (x != sptrs().end()) {
283                 sptrs().erase (x);
284                 if (debug_out) {
285                         cerr << "Removed sp for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
286                 }
287         }
288 }
289
290 void
291 boost_debug_shared_ptr_constructor (void const *sp, volatile void const *obj, int use_count)
292 {
293         if (is_interesting_object (obj)) {
294                 Glib::Threads::Mutex::Lock guard (the_lock());
295                 pair<void const*, SPDebug*> newpair;
296
297                 newpair.first = sp;
298                 newpair.second = new SPDebug (new Backtrace());
299
300                 sptrs().insert (newpair);
301                 if (debug_out) {
302                         cerr << "Stored constructor for " << obj << " @ " << sp << " UC = " << use_count << " (total sp's = " << sptrs().size() << ')' << endl;
303                         cerr << *newpair.second << endl;
304                 }
305         }
306 }
307
308 void
309 boost_debug_count_ptrs ()
310 {
311         Glib::Threads::Mutex::Lock guard (the_lock());
312         // cerr << "Tracking " << interesting_pointers().size() << " interesting objects with " << sptrs().size () << " shared ptrs\n";
313 }
314
315 void
316 boost_debug_list_ptrs ()
317 {
318         Glib::Threads::Mutex::Lock guard (the_lock());
319
320         if (sptrs().empty()) {
321                 cerr << "There are no dangling shared ptrs\n";
322         } else {
323                 for (PointerMap::iterator x = sptrs().begin(); x != sptrs().end(); ++x) {
324                         cerr << "Shared ptr @ " << x->first << " history: "
325                              << *x->second
326                              << endl;
327                 }
328         }
329 }
330
331 namespace boost {
332
333 void sp_scalar_constructor_hook( void *, std::size_t, void *)
334 {
335 }
336
337 void sp_scalar_destructor_hook( void *, std::size_t, void *)
338 {
339 }
340
341 void sp_counter_ref_hook (void* /*pn*/, long /* use count */)
342 {
343 }
344
345 void sp_counter_release_hook (void* /*pn*/, long /*use_count*/)
346 {
347 }
348
349 void sp_array_constructor_hook(void *)
350 {
351 }
352
353 void sp_array_destructor_hook(void *)
354 {
355 }
356
357 void sp_scalar_constructor_hook(void *)
358 {
359 }
360
361 void sp_scalar_destructor_hook(void *)
362 {
363 }
364
365 }