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