cleanup up cleanup at session destruction; clarify the meaning of 3 signals (DropRefe...
[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 = 5; 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 void
140 boost_debug_shared_ptr_mark_interesting (void* ptr, const char* type)
141 {
142         Glib::Mutex::Lock guard (the_lock);
143         pair<void*,const char*> newpair (ptr, type);
144         interesting_pointers.insert (newpair);
145         // cerr << "Interesting object @ " << ptr << " of type " << type << endl;
146 }
147
148 void
149 boost_debug_shared_ptr_operator_equals (void const *sp, void const *obj, int)
150 {
151         if (is_interesting_object (obj)) {
152                 cerr << "sp @ " << sp << " assigned\n";
153         }
154 }
155
156 void
157 boost_debug_shared_ptr_reset (void const *sp, void const *obj, int)
158 {
159         if (is_interesting_object (obj)) {
160                 cerr << "sp @ " << sp << " reset\n";
161         }
162 }
163
164 void
165 boost_debug_shared_ptr_destructor (void const *sp, void const *obj, int use_count)
166 {
167         Glib::Mutex::Lock guard (the_lock);
168         PointerMap::iterator x = sptrs.find (sp);
169
170         if (x != sptrs.end()) {
171                 sptrs.erase (x);
172                 // cerr << "Removed sp for " << obj << " @ " << sp << endl;
173         }
174 }
175
176 void
177 boost_debug_shared_ptr_constructor (void const *sp, void const *obj, int use_count)
178 {
179         if (is_interesting_object (obj)) {
180                 Glib::Mutex::Lock guard (the_lock);
181                 pair<void const*, SPDebug*> newpair;
182
183                 newpair.first = sp;
184                 newpair.second = new SPDebug (new Backtrace());
185
186                 sptrs.insert (newpair);
187                 // cerr << "Stored constructor for " << obj << " @ " << sp << endl;
188         }
189 }
190
191 void
192 boost_debug_list_ptrs ()
193 {
194         Glib::Mutex::Lock guard (the_lock);
195
196         if (sptrs.empty()) {
197                 cerr << "There are no dangling shared ptrs\n";
198         } else {
199                 for (PointerMap::iterator x = sptrs.begin(); x != sptrs.end(); ++x) {
200                         cerr << "Shared ptr @ " << x->first << " history: "
201                              << *x->second
202                              << endl;
203                 }
204         }
205 }
206
207 namespace boost {
208
209 void sp_scalar_constructor_hook( void * object, std::size_t size, void * pn )
210 {
211 }
212
213 void sp_scalar_destructor_hook( void * object, std::size_t size, void * pn )
214 {
215 }
216
217 void sp_counter_ref_hook (void* pn, long use_count)
218 {
219 }
220
221 void sp_counter_release_hook (void* pn, long use_count) 
222 {
223 }
224
225 void sp_array_constructor_hook(void * p)
226 {
227 }
228
229 void sp_array_destructor_hook(void * p)
230 {
231 }
232
233 void sp_scalar_constructor_hook(void * p)
234 {
235 }
236
237 void sp_scalar_destructor_hook(void * p)
238 {
239 }
240
241 }