b2c4c359308b59c614d5f8df058313aaf3b20151
[goodguy/cinelerra.git] / bctrace.h
1 /*
2  * CINELERRA
3  * Copyright (C) 2016-2020 William Morrow
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published
7  * by 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, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20
21
22 #ifndef __BC_TRACE_H__
23 #define __BC_TRACE_H__
24
25 #include "arraylist.h"
26 #include "linklist.h"
27 #include "bctrace.inc"
28 #include "bcwindowbase.inc"
29 #include "cstrdup.h"
30 #include <pthread.h>
31
32 #ifdef BOOBY
33 #define BT if( top_level->display_lock_owner != pthread_self() ) booby();
34 void booby();
35 #else
36 #define BT
37 #define booby(s) do {} while(0)
38 #endif
39
40 class BC_Trace
41 {
42 public:
43         BC_Trace();
44         ~BC_Trace();
45
46         static BC_Trace *global_trace;
47         static void reset_locks();
48
49         static void delete_temps();
50         static void set_temp(char *string);
51         static void unset_temp(char *string);
52
53         static void enable_locks();
54         static void disable_locks();
55         static int set_lock(const char *title, const char *location, trace_info *info);
56         static void set_lock2(int table_id, trace_info *info);
57         static void unset_lock2(int table_id, trace_info *info);
58         static void unset_lock(trace_info *info);
59 // Used in lock destructors so takes away all references
60         static void unset_all_locks(trace_info *info);
61         static void clear_locks_tid(pthread_t tid);
62
63         static void new_trace(const char *text);
64         static void new_trace(const char *file, const char *function, int line);
65         static void delete_traces();
66
67         static void enable_memory();
68         static void disable_memory();
69         static void set_buffer(int size, void *ptr, const char* location);
70 // This one returns 1 if the buffer wasn't found.
71         static int unset_buffer(void *ptr);
72         static void lock_locks(const char *s);
73         static void unlock_locks();
74
75         static void dump_traces(FILE *fp=stdout);
76         static void dump_locks(FILE *fp=stdout);
77         static void dump_buffers(FILE *fp=stdout);
78         static void dump_threads(FILE *fp=stdout);
79
80         static void dump_shm_stat(const char *fn, FILE *fp=stdout);
81         static void dump_shm_stats(FILE *fp=stdout);
82 };
83
84 class bc_trace_list : public List<trace_item> {
85 public:
86         void clear() { while( last ) remove(last); }
87         bc_trace_list() {}
88         ~bc_trace_list() { clear(); }
89 };
90
91 class bc_trace_t : public bc_trace_list {
92 public:
93         int size;
94         bc_trace_t() : size(0) {}
95         ~bc_trace_t() {}
96 };
97
98 class bc_trace_spin : public bc_trace_t {
99         pthread_spinlock_t spin;
100 public:
101         void *operator new(size_t n) { return (void*) malloc(n); }
102         void operator delete(void *t, size_t n) { free(t); }
103
104         void lock() { pthread_spin_lock(&spin); }
105         void unlock() { pthread_spin_unlock(&spin); }
106         bc_trace_spin() { pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE); }
107         ~bc_trace_spin() { pthread_spin_destroy(&spin); }
108 };
109
110 class bc_trace_mutex : public bc_trace_t {
111         pthread_mutex_t mutex;
112 public:
113         void *operator new(size_t n) { return (void*) malloc(n); }
114         void operator delete(void *t, size_t n) { free(t); }
115
116         void lock() { pthread_mutex_lock(&mutex); }
117         void unlock() { pthread_mutex_unlock(&mutex); }
118         bc_trace_mutex() { pthread_mutex_init(&mutex, 0); }
119         ~bc_trace_mutex() { pthread_mutex_destroy(&mutex); }
120 };
121
122 extern bc_trace_mutex execution_table;
123 extern bc_trace_mutex memory_table;
124 extern bc_trace_mutex lock_table;
125 extern bc_trace_mutex file_table;
126 extern "C" void dump();
127
128 class trace_item : public ListItem<trace_item> {
129 public:
130         bc_trace_t &table;
131         trace_item(bc_trace_t &t);
132         ~trace_item();
133 };
134
135 class execution_item : public trace_item {
136 public:
137         void *operator new(size_t n) { return (void*) malloc(n); }
138         void operator delete(void *t, size_t n) { free(t); }
139
140         const char *value;
141         void clear() { delete [] value;  value = 0; }
142         void set(const char *v) { delete [] value;  value = cstrdup(v); }
143
144         execution_item() : trace_item(execution_table) { value = 0; }
145         ~execution_item() { clear(); }
146 };
147
148 class lock_item : public trace_item {
149         static int table_id;
150 public:
151         void *operator new(size_t n) { return (void*) malloc(n); }
152         void operator delete(void *t, size_t n) { free(t); }
153
154         trace_info *info;
155         const char *title;
156         const char *loc;
157         int is_owner;
158         int id;
159         pthread_t tid;
160         void set(trace_info *info, const char *title, const char *loc) {
161                 this->info = info;  this->title = title;
162                 this->loc = loc;  this->is_owner = 0;
163                 this->id = table_id++;  this->tid = pthread_self();
164         }
165         void clear() {
166                 this->info = 0;  this->title = 0; this->loc = 0;
167                 this->is_owner = 0;  this->id = -1;  this->tid = 0;
168         }
169
170         lock_item() : trace_item(lock_table) { clear(); }
171         ~lock_item() {}
172 };
173
174 class memory_item : public trace_item {
175 public:
176         void *operator new(size_t n) { return (void*) malloc(n); }
177         void operator delete(void *t, size_t n) { free(t); }
178
179         int size;
180         void *ptr;
181         const char *loc;
182
183         memory_item(int size, void *ptr, const char *loc)
184          : trace_item(memory_table) {
185                 this->size = size; this->ptr = ptr; this->loc = loc;
186         }
187         ~memory_item() {}
188 };
189
190 class file_item : public trace_item {
191 public:
192         void *operator new(size_t n) { return (void*) malloc(n); }
193         void operator delete(void *t, size_t n) { free(t); }
194
195         const char *value;
196         void clear() { delete [] value;  value = 0; }
197         void set(const char *v) { delete [] value;  value = cstrdup(v); }
198
199         file_item() : trace_item(file_table) { value = 0; }
200         ~file_item() { clear(); }
201 };
202
203 // track unjoined threads at termination
204 #ifdef TRACE_THREADS
205
206 class TheLock {
207 public:
208         pthread_mutex_t the_lock;
209
210         void lock() { pthread_mutex_lock(&the_lock); }
211         void unlock() { pthread_mutex_unlock(&the_lock); }
212
213         void init() {
214                 pthread_mutexattr_t attr;
215                 pthread_mutexattr_init(&attr);
216                 pthread_mutex_init(&the_lock, &attr);
217         }
218         void finit() {
219                 pthread_mutex_destroy(&the_lock);
220         }
221         void reset() { finit();  init(); }
222
223         TheLock()  { init();  }
224         ~TheLock() { finit(); }
225 };
226
227 class TheLocker {
228 public:
229         static TheLock the_lock;
230         static void reset() { the_lock.reset(); }
231
232         TheLocker() { the_lock.lock(); }
233         ~TheLocker() { the_lock.unlock(); }
234 };
235
236 class TheDbg {
237 public:
238         pthread_t tid, owner;  const char *name;
239         TheDbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
240         ~TheDbg() {}
241 };
242
243
244 class TheList : public ArrayList<TheDbg *> {
245 public:
246         static TheList the_list;
247         static void dump_threads(FILE *fp);
248         static void dbg_add(pthread_t tid, pthread_t owner, const char *nm);
249         static void dbg_del(pthread_t tid);
250         static void reset() { the_list.remove_all_objects(); TheLocker::reset(); }
251         void check() {
252                 int i = the_list.size();
253                 if( !i ) return;
254                 printf("unjoined tids / owner %d\n", i);
255                 while( --i >= 0 ) printf("  %016lx / %016lx %s\n",
256                         (unsigned long)the_list[i]->tid,
257                         (unsigned long)the_list[i]->owner,
258                         the_list[i]->name);
259         }
260          TheList() {}
261         ~TheList() { check(); reset(); }
262 };
263
264 #endif
265
266 #endif