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