7 #include "bcwindowbase.inc"
12 #define BT if( top_level->display_lock_owner != pthread_self() ) booby();
16 #define booby(s) do {} while(0)
25 static BC_Trace *global_trace;
26 static void reset_locks();
28 static void delete_temps();
29 static void set_temp(char *string);
30 static void unset_temp(char *string);
32 static void enable_locks();
33 static void disable_locks();
34 static int set_lock(const char *title, const char *location, trace_info *info);
35 static void set_lock2(int table_id, trace_info *info);
36 static void unset_lock2(int table_id, trace_info *info);
37 static void unset_lock(trace_info *info);
38 // Used in lock destructors so takes away all references
39 static void unset_all_locks(trace_info *info);
40 static void clear_locks_tid(pthread_t tid);
42 static void new_trace(const char *text);
43 static void new_trace(const char *file, const char *function, int line);
44 static void delete_traces();
46 static void enable_memory();
47 static void disable_memory();
48 static void set_buffer(int size, void *ptr, const char* location);
49 // This one returns 1 if the buffer wasn't found.
50 static int unset_buffer(void *ptr);
51 static void lock_locks(const char *s);
52 static void unlock_locks();
54 static void dump_traces(FILE *fp=stdout);
55 static void dump_locks(FILE *fp=stdout);
56 static void dump_buffers(FILE *fp=stdout);
57 static void dump_threads(FILE *fp=stdout);
59 static void dump_shm_stat(const char *fn, FILE *fp=stdout);
60 static void dump_shm_stats(FILE *fp=stdout);
63 class bc_trace_list : public List<trace_item> {
65 void clear() { while( last ) remove(last); }
67 ~bc_trace_list() { clear(); }
70 class bc_trace_t : public bc_trace_list {
73 bc_trace_t() : size(0) {}
77 class bc_trace_spin : public bc_trace_t {
78 pthread_spinlock_t spin;
80 void *operator new(size_t n) { return (void*) malloc(n); }
81 void operator delete(void *t, size_t n) { free(t); }
83 void lock() { pthread_spin_lock(&spin); }
84 void unlock() { pthread_spin_unlock(&spin); }
85 bc_trace_spin() { pthread_spin_init(&spin, PTHREAD_PROCESS_PRIVATE); }
86 ~bc_trace_spin() { pthread_spin_destroy(&spin); }
89 class bc_trace_mutex : public bc_trace_t {
90 pthread_mutex_t mutex;
92 void *operator new(size_t n) { return (void*) malloc(n); }
93 void operator delete(void *t, size_t n) { free(t); }
95 void lock() { pthread_mutex_lock(&mutex); }
96 void unlock() { pthread_mutex_unlock(&mutex); }
97 bc_trace_mutex() { pthread_mutex_init(&mutex, 0); }
98 ~bc_trace_mutex() { pthread_mutex_destroy(&mutex); }
101 extern bc_trace_mutex execution_table;
102 extern bc_trace_mutex memory_table;
103 extern bc_trace_mutex lock_table;
104 extern bc_trace_mutex file_table;
105 extern "C" void dump();
107 class trace_item : public ListItem<trace_item> {
110 trace_item(bc_trace_t &t);
114 class execution_item : public trace_item {
116 void *operator new(size_t n) { return (void*) malloc(n); }
117 void operator delete(void *t, size_t n) { free(t); }
120 void clear() { delete [] value; value = 0; }
121 void set(const char *v) { delete [] value; value = cstrdup(v); }
123 execution_item() : trace_item(execution_table) { value = 0; }
124 ~execution_item() { clear(); }
127 class lock_item : public trace_item {
130 void *operator new(size_t n) { return (void*) malloc(n); }
131 void operator delete(void *t, size_t n) { free(t); }
139 void set(trace_info *info, const char *title, const char *loc) {
140 this->info = info; this->title = title;
141 this->loc = loc; this->is_owner = 0;
142 this->id = table_id++; this->tid = pthread_self();
145 this->info = 0; this->title = 0; this->loc = 0;
146 this->is_owner = 0; this->id = -1; this->tid = 0;
149 lock_item() : trace_item(lock_table) { clear(); }
153 class memory_item : public trace_item {
155 void *operator new(size_t n) { return (void*) malloc(n); }
156 void operator delete(void *t, size_t n) { free(t); }
162 memory_item(int size, void *ptr, const char *loc)
163 : trace_item(memory_table) {
164 this->size = size; this->ptr = ptr; this->loc = loc;
169 class file_item : public trace_item {
171 void *operator new(size_t n) { return (void*) malloc(n); }
172 void operator delete(void *t, size_t n) { free(t); }
175 void clear() { delete [] value; value = 0; }
176 void set(const char *v) { delete [] value; value = cstrdup(v); }
178 file_item() : trace_item(file_table) { value = 0; }
179 ~file_item() { clear(); }
182 // track unjoined threads at termination
187 pthread_mutex_t the_lock;
189 void lock() { pthread_mutex_lock(&the_lock); }
190 void unlock() { pthread_mutex_unlock(&the_lock); }
193 pthread_mutexattr_t attr;
194 pthread_mutexattr_init(&attr);
195 pthread_mutex_init(&the_lock, &attr);
198 pthread_mutex_destroy(&the_lock);
200 void reset() { finit(); init(); }
202 TheLock() { init(); }
203 ~TheLock() { finit(); }
208 static TheLock the_lock;
209 static void reset() { the_lock.reset(); }
211 TheLocker() { the_lock.lock(); }
212 ~TheLocker() { the_lock.unlock(); }
217 pthread_t tid, owner; const char *name;
218 TheDbg(pthread_t t, pthread_t o, const char *nm) { tid = t; owner = o; name = nm; }
223 class TheList : public ArrayList<TheDbg *> {
225 static TheList the_list;
226 static void dump_threads(FILE *fp);
227 static void dbg_add(pthread_t tid, pthread_t owner, const char *nm);
228 static void dbg_del(pthread_t tid);
229 static void reset() { the_list.remove_all_objects(); TheLocker::reset(); }
231 int i = the_list.size();
233 printf("unjoined tids / owner %d\n", i);
234 while( --i >= 0 ) printf(" %016lx / %016lx %s\n",
235 (unsigned long)the_list[i]->tid,
236 (unsigned long)the_list[i]->owner,
240 ~TheList() { check(); reset(); }