Invert Pan-Azimuth (up means left)
[ardour.git] / libs / pbd / boost_debug.cc
1 /*
2  * Copyright (C) 2009-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include "libpbd-config.h"
21
22 #ifdef HAVE_EXECINFO
23 #include <execinfo.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <iostream>
28 #include <map>
29 #include <set>
30 #include <vector>
31 #include <glibmm/threads.h>
32 #include <boost/shared_ptr.hpp>
33
34 #include "pbd/stacktrace.h"
35 #include "pbd/boost_debug.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 Backtrace::Backtrace()
50 {
51 #ifdef HAVE_EXECINFO
52         size = ::backtrace (trace, 200);
53 #endif
54 }
55
56 std::ostream&
57 Backtrace::print (std::ostream& str) const
58 {
59         char **strings = 0;
60         size_t i;
61
62         if (size) {
63 #ifdef HAVE_EXECINFO
64                 strings = ::backtrace_symbols (trace, size);
65 #endif
66                 if (strings) {
67                         for (i = 3; i < 5+18 && i < size; i++) {
68                                 str << strings[i] << std::endl;
69                         }
70                         free (strings);
71                 }
72         }
73
74         return str;
75 }
76
77 struct BTPair {
78
79         Backtrace* ref;
80         Backtrace* rel;
81
82         BTPair (Backtrace* bt) : ref (bt), rel (0) {}
83         ~BTPair () { }
84 };
85
86 std::ostream& operator<<(std::ostream& str, const BTPair& btp) {
87         str << "*********************************************\n";
88         if (btp.ref) str << *btp.ref << std::endl;
89         str << "Rel:\n";
90         if (btp.rel) str << *btp.rel << std::endl;
91         return str;
92 }
93
94 struct SPDebug {
95         Backtrace* constructor;
96         Backtrace* destructor;
97
98         SPDebug (Backtrace* c) : constructor (c), destructor (0) {}
99         ~SPDebug () {
100                 delete constructor;
101                 delete destructor;
102         }
103 };
104
105 std::ostream& operator<< (std::ostream& str, const SPDebug& spd)
106 {
107         str << "Constructor :" << std::endl;
108         if (spd.constructor) {
109                 str << *spd.constructor << std::endl;
110         }
111
112         return str;
113 }
114
115 typedef std::multimap<volatile void const*,SPDebug*> PointerMap;
116 typedef std::map<volatile void const*,const char*> IPointerMap;
117
118 using namespace std;
119
120 static PointerMap* _sptrs;
121 PointerMap& sptrs()
122 {
123         if (_sptrs == 0) {
124                 _sptrs = new PointerMap;
125         }
126         return *_sptrs;
127 }
128
129 static IPointerMap* _interesting_pointers;
130 IPointerMap& interesting_pointers()
131 {
132         if (_interesting_pointers == 0) {
133                 _interesting_pointers = new IPointerMap;
134         }
135         return *_interesting_pointers;
136 }
137
138 static Glib::Threads::Mutex* _the_lock;
139 static Glib::Threads::Mutex& the_lock()
140 {
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 (volatile 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, volatile 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, volatile 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 }