3 * Copyright (C) 2016-2020 William Morrow
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.
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.
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
22 #ifndef __BC_TRACE_H__
23 #define __BC_TRACE_H__
25 #include "arraylist.h"
27 #include "bctrace.inc"
28 #include "bcwindowbase.inc"
33 #define BT if( top_level->display_lock_owner != pthread_self() ) booby();
37 #define booby(s) do {} while(0)
46 static BC_Trace *global_trace;
47 static void reset_locks();
49 static void delete_temps();
50 static void set_temp(char *string);
51 static void unset_temp(char *string);
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);
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();
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();
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);
80 static void dump_shm_stat(const char *fn, FILE *fp=stdout);
81 static void dump_shm_stats(FILE *fp=stdout);
84 class bc_trace_list : public List<trace_item> {
86 void clear() { while( last ) remove(last); }
88 ~bc_trace_list() { clear(); }
91 class bc_trace_t : public bc_trace_list {
94 bc_trace_t() : size(0) {}
98 class bc_trace_spin : public bc_trace_t {
99 pthread_spinlock_t spin;
101 void *operator new(size_t n) { return (void*) malloc(n); }
102 void operator delete(void *t, size_t n) { free(t); }
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); }
110 class bc_trace_mutex : public bc_trace_t {
111 pthread_mutex_t mutex;
113 void *operator new(size_t n) { return (void*) malloc(n); }
114 void operator delete(void *t, size_t n) { free(t); }
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); }
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();
128 class trace_item : public ListItem<trace_item> {
131 trace_item(bc_trace_t &t);
135 class execution_item : public trace_item {
137 void *operator new(size_t n) { return (void*) malloc(n); }
138 void operator delete(void *t, size_t n) { free(t); }
141 void clear() { delete [] value; value = 0; }
142 void set(const char *v) { delete [] value; value = cstrdup(v); }
144 execution_item() : trace_item(execution_table) { value = 0; }
145 ~execution_item() { clear(); }
148 class lock_item : public trace_item {
151 void *operator new(size_t n) { return (void*) malloc(n); }
152 void operator delete(void *t, size_t n) { free(t); }
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();
166 this->info = 0; this->title = 0; this->loc = 0;
167 this->is_owner = 0; this->id = -1; this->tid = 0;
170 lock_item() : trace_item(lock_table) { clear(); }
174 class memory_item : public trace_item {
176 void *operator new(size_t n) { return (void*) malloc(n); }
177 void operator delete(void *t, size_t n) { free(t); }
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;
190 class file_item : public trace_item {
192 void *operator new(size_t n) { return (void*) malloc(n); }
193 void operator delete(void *t, size_t n) { free(t); }
196 void clear() { delete [] value; value = 0; }
197 void set(const char *v) { delete [] value; value = cstrdup(v); }
199 file_item() : trace_item(file_table) { value = 0; }
200 ~file_item() { clear(); }
203 // track unjoined threads at termination
208 pthread_mutex_t the_lock;
210 void lock() { pthread_mutex_lock(&the_lock); }
211 void unlock() { pthread_mutex_unlock(&the_lock); }
214 pthread_mutexattr_t attr;
215 pthread_mutexattr_init(&attr);
216 pthread_mutex_init(&the_lock, &attr);
219 pthread_mutex_destroy(&the_lock);
221 void reset() { finit(); init(); }
223 TheLock() { init(); }
224 ~TheLock() { finit(); }
229 static TheLock the_lock;
230 static void reset() { the_lock.reset(); }
232 TheLocker() { the_lock.lock(); }
233 ~TheLocker() { the_lock.unlock(); }
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; }
244 class TheList : public ArrayList<TheDbg *> {
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(); }
252 int i = the_list.size();
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,
261 ~TheList() { check(); reset(); }