00001 #include "bcsignals.h"
00002 #include "bcwindowbase.inc"
00003 #include <stdio.h>
00004 #include <stdlib.h>
00005 #include <string.h>
00006 #include <unistd.h>
00007
00008 BC_Signals* BC_Signals::global_signals = 0;
00009 static int signal_done = 0;
00010 static int table_id = 0;
00011
00012 static bc_locktrace_t* new_bc_locktrace(void *ptr,
00013 char *title,
00014 char *location)
00015 {
00016 bc_locktrace_t *result = (bc_locktrace_t*)malloc(sizeof(bc_locktrace_t));
00017 result->ptr = ptr;
00018 result->title = title;
00019 result->location = location;
00020 result->is_owner = 0;
00021 result->id = table_id++;
00022 return result;
00023 }
00024
00025
00026
00027
00028
00029 typedef struct
00030 {
00031 int size;
00032 void *ptr;
00033 char *location;
00034 } bc_buffertrace_t;
00035
00036 static bc_buffertrace_t* new_bc_buffertrace(int size, void *ptr, char *location)
00037 {
00038 bc_buffertrace_t *result = (bc_buffertrace_t*)malloc(sizeof(bc_buffertrace_t));
00039 result->size = size;
00040 result->ptr = ptr;
00041 result->location = location;
00042 return result;
00043 }
00044
00045
00046
00047
00048
00049
00050
00051 typedef struct
00052 {
00053 void **values;
00054 int size;
00055 int allocation;
00056 } bc_table_t;
00057
00058 static void* append_table(bc_table_t *table, void *ptr)
00059 {
00060 if(table->allocation <= table->size)
00061 {
00062 if(table->allocation)
00063 {
00064 int new_allocation = table->allocation * 2;
00065 void **new_values = (void**)calloc(new_allocation, sizeof(void*));
00066 memcpy(new_values, table->values, sizeof(void*) * table->size);
00067 free(table->values);
00068 table->values = new_values;
00069 table->allocation = new_allocation;
00070 }
00071 else
00072 {
00073 table->allocation = 4096;
00074 table->values = (void**)calloc(table->allocation, sizeof(void*));
00075 }
00076 }
00077
00078 table->values[table->size++] = ptr;
00079 return ptr;
00080 }
00081
00082 static void clear_table(bc_table_t *table, int delete_objects)
00083 {
00084 if(delete_objects)
00085 {
00086 for(int i = 0; i < table->size; i++)
00087 {
00088 free(table->values[i]);
00089 }
00090 }
00091 table->size = 0;
00092 }
00093
00094 static void clear_table_entry(bc_table_t *table, int number, int delete_object)
00095 {
00096 if(delete_object) free(table->values[number]);
00097 for(int i = number; i < table->size - 1; i++)
00098 {
00099 table->values[i] = table->values[i + 1];
00100 }
00101 table->size--;
00102 }
00103
00104
00105
00106 static bc_table_t execution_table = { 0, 0, 0 };
00107
00108
00109 static bc_table_t lock_table = { 0, 0, 0 };
00110
00111
00112 static bc_table_t memory_table = { 0, 0, 0 };
00113
00114 static bc_table_t temp_files = { 0, 0, 0 };
00115
00116
00117 static pthread_mutex_t *lock = 0;
00118 static pthread_mutex_t *handler_lock = 0;
00119
00120 static int trace_memory = 0;
00121
00122
00123 static char* signal_titles[] =
00124 {
00125 "NULL",
00126 "SIGHUP",
00127 "SIGINT",
00128 "SIGQUIT",
00129 "SIGILL",
00130 "SIGTRAP",
00131 "SIGABRT",
00132 "SIGBUS",
00133 "SIGFPE",
00134 "SIGKILL",
00135 "SIGUSR1",
00136 "SIGSEGV",
00137 "SIGUSR2",
00138 "SIGPIPE",
00139 "SIGALRM",
00140 "SIGTERM"
00141 };
00142
00143 static void signal_entry(int signum)
00144 {
00145 signal(signum, SIG_DFL);
00146
00147 pthread_mutex_lock(handler_lock);
00148 if(signal_done)
00149 {
00150 pthread_mutex_unlock(handler_lock);
00151 exit(0);
00152 }
00153
00154 signal_done = 1;
00155 pthread_mutex_unlock(handler_lock);
00156
00157
00158 printf("signal_entry: got %s my pid=%d execution table size=%d:\n",
00159 signal_titles[signum],
00160 getpid(),
00161 execution_table.size);
00162
00163 BC_Signals::dump_traces();
00164 BC_Signals::dump_locks();
00165 BC_Signals::dump_buffers();
00166 BC_Signals::delete_temps();
00167
00168
00169 BC_Signals::global_signals->signal_handler(signum);
00170
00171 exit(0);
00172 }
00173
00174 static void signal_entry_recoverable(int signum)
00175 {
00176 printf("signal_entry_recoverable: got %s my pid=%d\n",
00177 signal_titles[signum],
00178 getpid());
00179 }
00180
00181 BC_Signals::BC_Signals()
00182 {
00183 }
00184
00185 void BC_Signals::dump_traces()
00186 {
00187
00188 if(execution_table.size)
00189 {
00190 for(int i = 0; i < execution_table.size; i++)
00191 printf(" %s\n", execution_table.values[i]);
00192 }
00193
00194 }
00195
00196 void BC_Signals::dump_locks()
00197 {
00198
00199 printf("signal_entry: lock table size=%d\n", lock_table.size);
00200 for(int i = 0; i < lock_table.size; i++)
00201 {
00202 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
00203 printf(" %p %s %s %s\n",
00204 table->ptr,
00205 table->title,
00206 table->location,
00207 table->is_owner ? "*" : "");
00208 }
00209
00210 }
00211
00212 void BC_Signals::dump_buffers()
00213 {
00214 pthread_mutex_lock(lock);
00215
00216 printf("BC_Signals::dump_buffers: buffer table size=%d\n", memory_table.size);
00217 for(int i = 0; i < memory_table.size; i++)
00218 {
00219 bc_buffertrace_t *entry = (bc_buffertrace_t*)memory_table.values[i];
00220 printf(" %d %p %s\n", entry->size, entry->ptr, entry->location);
00221 }
00222 pthread_mutex_unlock(lock);
00223 }
00224
00225 void BC_Signals::delete_temps()
00226 {
00227 pthread_mutex_lock(lock);
00228 printf("BC_Signals::delete_temps: deleting %d temp files\n", temp_files.size);
00229 for(int i = 0; i < temp_files.size; i++)
00230 {
00231 printf(" %s\n", (char*)temp_files.values[i]);
00232 remove((char*)temp_files.values[i]);
00233 }
00234 pthread_mutex_unlock(lock);
00235 }
00236
00237 void BC_Signals::set_temp(char *string)
00238 {
00239 char *new_string = strdup(string);
00240 append_table(&temp_files, new_string);
00241 }
00242
00243 void BC_Signals::unset_temp(char *string)
00244 {
00245 for(int i = 0; i < temp_files.size; i++)
00246 {
00247 if(!strcmp((char*)temp_files.values[i], string))
00248 {
00249 clear_table_entry(&temp_files, i, 1);
00250 break;
00251 }
00252 }
00253 }
00254
00255
00256 void BC_Signals::initialize()
00257 {
00258 BC_Signals::global_signals = this;
00259 lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
00260 handler_lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
00261 pthread_mutex_init(lock, 0);
00262 pthread_mutex_init(handler_lock, 0);
00263
00264 initialize2();
00265 }
00266
00267
00268 void BC_Signals::initialize2()
00269 {
00270 signal(SIGHUP, signal_entry);
00271 signal(SIGINT, signal_entry);
00272 signal(SIGQUIT, signal_entry);
00273
00274
00275 signal(SIGSEGV, signal_entry);
00276 signal(SIGTERM, signal_entry);
00277 signal(SIGFPE, signal_entry_recoverable);
00278 signal(SIGPIPE, signal_entry_recoverable);
00279 }
00280
00281
00282 void BC_Signals::signal_handler(int signum)
00283 {
00284 printf("BC_Signals::signal_handler\n");
00285
00286 }
00287
00288 char* BC_Signals::sig_to_str(int number)
00289 {
00290 return signal_titles[number];
00291 }
00292
00293 #define TOTAL_TRACES 100
00294
00295 void BC_Signals::new_trace(char *text)
00296 {
00297 if(!global_signals) return;
00298 pthread_mutex_lock(lock);
00299 if(execution_table.size >= TOTAL_TRACES)
00300 clear_table(&execution_table, 1);
00301 append_table(&execution_table, strdup(text));
00302 pthread_mutex_unlock(lock);
00303 }
00304
00305 void BC_Signals::new_trace(const char *file, const char *function, int line)
00306 {
00307 char string[BCTEXTLEN];
00308 snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
00309 new_trace(string);
00310 }
00311
00312 void BC_Signals::delete_traces()
00313 {
00314 if(!global_signals) return;
00315 pthread_mutex_lock(lock);
00316 clear_table(&execution_table, 0);
00317 pthread_mutex_unlock(lock);
00318 }
00319
00320 #define TOTAL_LOCKS 100
00321
00322 int BC_Signals::set_lock(void *ptr,
00323 char *title,
00324 char *location)
00325 {
00326 if(!global_signals) return 0;
00327 bc_locktrace_t *table = 0;
00328 int id_return = 0;
00329
00330 pthread_mutex_lock(lock);
00331 if(lock_table.size >= TOTAL_LOCKS)
00332 clear_table(&lock_table, 0);
00333
00334
00335 table = new_bc_locktrace(ptr, title, location);
00336 append_table(&lock_table, table);
00337 id_return = table->id;
00338
00339 pthread_mutex_unlock(lock);
00340 return id_return;
00341 }
00342
00343 void BC_Signals::set_lock2(int table_id)
00344 {
00345 if(!global_signals) return;
00346
00347 bc_locktrace_t *table = 0;
00348 pthread_mutex_lock(lock);
00349 for(int i = lock_table.size - 1; i >= 0; i--)
00350 {
00351 table = (bc_locktrace_t*)lock_table.values[i];
00352
00353 if(table->id == table_id)
00354 {
00355 table->is_owner = 1;
00356 pthread_mutex_unlock(lock);
00357 return;
00358 }
00359 }
00360 pthread_mutex_unlock(lock);
00361 }
00362
00363 void BC_Signals::unset_lock2(int table_id)
00364 {
00365 if(!global_signals) return;
00366
00367 bc_locktrace_t *table = 0;
00368 pthread_mutex_lock(lock);
00369 for(int i = lock_table.size - 1; i >= 0; i--)
00370 {
00371 table = (bc_locktrace_t*)lock_table.values[i];
00372 if(table->id == table_id)
00373 {
00374 clear_table_entry(&lock_table, i, 1);
00375 pthread_mutex_unlock(lock);
00376 return;
00377 }
00378 }
00379 pthread_mutex_unlock(lock);
00380 }
00381
00382 void BC_Signals::unset_lock(void *ptr)
00383 {
00384 if(!global_signals) return;
00385
00386 bc_locktrace_t *table = 0;
00387 pthread_mutex_lock(lock);
00388
00389
00390 for(int i = 0; i < lock_table.size; i++)
00391 {
00392 table = (bc_locktrace_t*)lock_table.values[i];
00393 if(table->ptr == ptr)
00394 {
00395 if(table->is_owner)
00396 {
00397 clear_table_entry(&lock_table, i, 1);
00398 pthread_mutex_unlock(lock);
00399 return;
00400 }
00401 }
00402 }
00403
00404 pthread_mutex_unlock(lock);
00405 }
00406
00407
00408 void BC_Signals::unset_all_locks(void *ptr)
00409 {
00410 if(!global_signals) return;
00411 pthread_mutex_lock(lock);
00412
00413 for(int i = 0; i < lock_table.size; i++)
00414 {
00415 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
00416 if(table->ptr == ptr)
00417 {
00418 clear_table_entry(&lock_table, i, 1);
00419 }
00420 }
00421 pthread_mutex_unlock(lock);
00422 }
00423
00424
00425 void BC_Signals::enable_memory()
00426 {
00427 trace_memory = 1;
00428 }
00429
00430 void BC_Signals::disable_memory()
00431 {
00432 trace_memory = 0;
00433 }
00434
00435
00436 void BC_Signals::set_buffer(int size, void *ptr, char* location)
00437 {
00438 if(!global_signals) return;
00439 if(!trace_memory) return;
00440
00441 pthread_mutex_lock(lock);
00442 append_table(&memory_table, new_bc_buffertrace(size, ptr, location));
00443 pthread_mutex_unlock(lock);
00444 }
00445
00446 int BC_Signals::unset_buffer(void *ptr)
00447 {
00448 if(!global_signals) return 0;
00449 if(!trace_memory) return 0;
00450 pthread_mutex_lock(lock);
00451 for(int i = 0; i < memory_table.size; i++)
00452 {
00453 if(((bc_buffertrace_t*)memory_table.values[i])->ptr == ptr)
00454 {
00455 clear_table_entry(&memory_table, i, 1);
00456 pthread_mutex_unlock(lock);
00457 return 0;
00458 }
00459 }
00460 pthread_mutex_unlock(lock);
00461 fprintf(stderr, "BC_Signals::unset_buffer buffer %p not found.\n", ptr);
00462 return 1;
00463 }
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 #ifdef TRACE_MEMORY
00478
00479
00480 void* operator new(size_t size)
00481 {
00482
00483 void *result = malloc(size);
00484 BUFFER(size, result, "new");
00485
00486 return result;
00487 }
00488
00489 void* operator new[](size_t size)
00490 {
00491
00492 void *result = malloc(size);
00493 BUFFER(size, result, "new []");
00494
00495 return result;
00496 }
00497
00498 void operator delete(void *ptr)
00499 {
00500
00501 UNBUFFER(ptr);
00502
00503 free(ptr);
00504 }
00505
00506 void operator delete[](void *ptr)
00507 {
00508
00509 UNBUFFER(ptr);
00510 free(ptr);
00511
00512 }
00513
00514
00515 #endif