r860: Merge 2.1:
[cinelerra_cv.git] / guicast / bcsignals.C
blobf339d285802687ef23966e5d2defddaa6628712f
1 #include "bcsignals.h"
2 #include "bcwindowbase.inc"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
8 BC_Signals* BC_Signals::global_signals = 0;
9 static int signal_done = 0;
10 static int table_id = 0;
12 static bc_locktrace_t* new_bc_locktrace(void *ptr, 
13         char *title, 
14         char *location)
16         bc_locktrace_t *result = (bc_locktrace_t*)malloc(sizeof(bc_locktrace_t));
17         result->ptr = ptr;
18         result->title = title;
19         result->location = location;
20         result->is_owner = 0;
21         result->id = table_id++;
22         return result;
29 typedef struct
31         int size;
32         void *ptr;
33         char *location;
34 } bc_buffertrace_t;
36 static bc_buffertrace_t* new_bc_buffertrace(int size, void *ptr, char *location)
38         bc_buffertrace_t *result = (bc_buffertrace_t*)malloc(sizeof(bc_buffertrace_t));
39         result->size = size;
40         result->ptr = ptr;
41         result->location = location;
42         return result;
50 // Need our own table to avoid recursion with the memory manager
51 typedef struct
53         void **values;
54         int size;
55         int allocation;
56 // This points to the next value to replace if the table wraps around
57         int current_value;
58 } bc_table_t;
60 static void* append_table(bc_table_t *table, void *ptr)
62         if(table->allocation <= table->size)
63         {
64                 if(table->allocation)
65                 {
66                         int new_allocation = table->allocation * 2;
67                         void **new_values = (void**)calloc(new_allocation, sizeof(void*));
68                         memcpy(new_values, table->values, sizeof(void*) * table->size);
69                         free(table->values);
70                         table->values = new_values;
71                         table->allocation = new_allocation;
72                 }
73                 else
74                 {
75                         table->allocation = 4096;
76                         table->values = (void**)calloc(table->allocation, sizeof(void*));
77                 }
78         }
80         table->values[table->size++] = ptr;
81         return ptr;
84 // Replace item in table pointed to by current_value and advance
85 // current_value
86 static void* overwrite_table(bc_table_t *table, void *ptr)
88         free(table->values[table->current_value]);
89         table->values[table->current_value++] = ptr;
90         if(table->current_value >= table->size) table->current_value = 0;
93 static void clear_table(bc_table_t *table, int delete_objects)
95         if(delete_objects)
96         {
97                 for(int i = 0; i < table->size; i++)
98                 {
99                         free(table->values[i]);
100                 }
101         }
102         table->size = 0;
105 static void clear_table_entry(bc_table_t *table, int number, int delete_object)
107         if(delete_object) free(table->values[number]);
108         for(int i = number; i < table->size - 1; i++)
109         {
110                 table->values[i] = table->values[i + 1];
111         }
112         table->size--;
116 // Table of functions currently running.
117 static bc_table_t execution_table = { 0, 0, 0, 0 };
119 // Table of locked positions
120 static bc_table_t lock_table = { 0, 0, 0, 0 };
122 // Table of buffers
123 static bc_table_t memory_table = { 0, 0, 0, 0 };
125 static bc_table_t temp_files = { 0, 0, 0, 0 };
127 // Can't use Mutex because it would be recursive
128 static pthread_mutex_t *lock = 0;
129 static pthread_mutex_t *handler_lock = 0;
130 // Don't trace memory until this is true to avoid initialization
131 static int trace_memory = 0;
134 static char* signal_titles[] =
136         "NULL",
137         "SIGHUP",
138         "SIGINT",
139         "SIGQUIT",
140         "SIGILL",
141         "SIGTRAP",
142         "SIGABRT",
143         "SIGBUS",
144         "SIGFPE",
145         "SIGKILL",
146         "SIGUSR1",
147         "SIGSEGV",
148         "SIGUSR2",
149         "SIGPIPE",
150         "SIGALRM",
151         "SIGTERM"
154 static void signal_entry(int signum)
156         signal(signum, SIG_DFL);
158         pthread_mutex_lock(handler_lock);
159         if(signal_done)
160         {
161                 pthread_mutex_unlock(handler_lock);
162                 exit(0);
163         }
165         signal_done = 1;
166         pthread_mutex_unlock(handler_lock);
169         printf("signal_entry: got %s my pid=%d execution table size=%d:\n", 
170                 signal_titles[signum],
171                 getpid(),
172                 execution_table.size);
174         BC_Signals::dump_traces();
175         BC_Signals::dump_locks();
176         BC_Signals::dump_buffers();
177         BC_Signals::delete_temps();
179 // Call user defined signal handler
180         BC_Signals::global_signals->signal_handler(signum);
182         abort();
185 static void signal_entry_recoverable(int signum)
187         printf("signal_entry_recoverable: got %s my pid=%d\n", 
188                 signal_titles[signum],
189                 getpid());
192 BC_Signals::BC_Signals()
196 void BC_Signals::dump_traces()
198 // Dump trace table
199         if(execution_table.size)
200         {
201                 for(int i = execution_table.current_value; i < execution_table.size; i++)
202                         printf("    %s\n", execution_table.values[i]);
203                 for(int i = 0; i < execution_table.current_value; i++)
204                         printf("    %s\n", execution_table.values[i]);
205         }
209 void BC_Signals::dump_locks()
211 // Dump lock table
212         printf("signal_entry: lock table size=%d\n", lock_table.size);
213         for(int i = 0; i < lock_table.size; i++)
214         {
215                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
216                 printf("    %p %s %s %s\n", 
217                         table->ptr,
218                         table->title,
219                         table->location,
220                         table->is_owner ? "*" : "");
221         }
225 void BC_Signals::dump_buffers()
227         pthread_mutex_lock(lock);
228 // Dump buffer table
229         printf("BC_Signals::dump_buffers: buffer table size=%d\n", memory_table.size);
230         for(int i = 0; i < memory_table.size; i++)
231         {
232                 bc_buffertrace_t *entry = (bc_buffertrace_t*)memory_table.values[i];
233                 printf("    %d %p %s\n", entry->size, entry->ptr, entry->location);
234         }
235         pthread_mutex_unlock(lock);
238 void BC_Signals::delete_temps()
240         pthread_mutex_lock(lock);
241         printf("BC_Signals::delete_temps: deleting %d temp files\n", temp_files.size);
242         for(int i = 0; i < temp_files.size; i++)
243         {
244                 printf("    %s\n", (char*)temp_files.values[i]);
245                 remove((char*)temp_files.values[i]);
246         }
247         pthread_mutex_unlock(lock);
250 void BC_Signals::set_temp(char *string)
252         char *new_string = strdup(string);
253         append_table(&temp_files, new_string);
256 void BC_Signals::unset_temp(char *string)
258         for(int i = 0; i < temp_files.size; i++)
259         {
260                 if(!strcmp((char*)temp_files.values[i], string))
261                 {
262                         clear_table_entry(&temp_files, i, 1);
263                         break;
264                 }
265         }
269 void BC_Signals::initialize()
271         BC_Signals::global_signals = this;
272         lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
273         handler_lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
274         pthread_mutex_init(lock, 0);
275         pthread_mutex_init(handler_lock, 0);
277         initialize2();
281 void BC_Signals::initialize2()
283         signal(SIGHUP, signal_entry);
284         signal(SIGINT, signal_entry);
285         signal(SIGQUIT, signal_entry);
286         // SIGKILL cannot be stopped
287         // signal(SIGKILL, signal_entry);
288         signal(SIGSEGV, signal_entry);
289         signal(SIGTERM, signal_entry);
290         signal(SIGFPE, signal_entry);
291         signal(SIGPIPE, signal_entry_recoverable);
295 void BC_Signals::signal_handler(int signum)
297 printf("BC_Signals::signal_handler\n");
298 //      exit(0);
301 char* BC_Signals::sig_to_str(int number)
303         return signal_titles[number];
306 #define TOTAL_TRACES 16
308 void BC_Signals::new_trace(char *text)
310         if(!global_signals) return;
311         pthread_mutex_lock(lock);
313 // Wrap around
314         if(execution_table.size >= TOTAL_TRACES)
315         {
316                 overwrite_table(&execution_table, strdup(text));
317 //              clear_table(&execution_table, 1);
318         }
319         else
320         {
321         append_table(&execution_table, strdup(text));
322         }
323         pthread_mutex_unlock(lock);
326 void BC_Signals::new_trace(const char *file, const char *function, int line)
328         char string[BCTEXTLEN];
329         snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
330         new_trace(string);
333 void BC_Signals::delete_traces()
335         if(!global_signals) return;
336         pthread_mutex_lock(lock);
337         clear_table(&execution_table, 0);
338         pthread_mutex_unlock(lock);
341 #define TOTAL_LOCKS 100
343 int BC_Signals::set_lock(void *ptr, 
344         char *title, 
345         char *location)
347         if(!global_signals) return 0;
348         bc_locktrace_t *table = 0;
349         int id_return = 0;
351         pthread_mutex_lock(lock);
352         if(lock_table.size >= TOTAL_LOCKS)
353                 clear_table(&lock_table, 0);
355 // Put new lock entry
356         table = new_bc_locktrace(ptr, title, location);
357         append_table(&lock_table, table);
358         id_return = table->id;
360         pthread_mutex_unlock(lock);
361         return id_return;
364 void BC_Signals::set_lock2(int table_id)
366         if(!global_signals) return;
368         bc_locktrace_t *table = 0;
369         pthread_mutex_lock(lock);
370         for(int i = lock_table.size - 1; i >= 0; i--)
371         {
372                 table = (bc_locktrace_t*)lock_table.values[i];
373 // Got it.  Hasn't been unlocked/deleted yet.
374                 if(table->id == table_id)
375                 {
376                         table->is_owner = 1;
377                         pthread_mutex_unlock(lock);
378                         return;
379                 }
380         }
381         pthread_mutex_unlock(lock);
384 void BC_Signals::unset_lock2(int table_id)
386         if(!global_signals) return;
388         bc_locktrace_t *table = 0;
389         pthread_mutex_lock(lock);
390         for(int i = lock_table.size - 1; i >= 0; i--)
391         {
392                 table = (bc_locktrace_t*)lock_table.values[i];
393                 if(table->id == table_id)
394                 {
395                         clear_table_entry(&lock_table, i, 1);
396                         pthread_mutex_unlock(lock);
397                         return;
398                 }
399         }
400         pthread_mutex_unlock(lock);
403 void BC_Signals::unset_lock(void *ptr)
405         if(!global_signals) return;
407         bc_locktrace_t *table = 0;
408         pthread_mutex_lock(lock);
410 // Take off currently held entry
411         for(int i = 0; i < lock_table.size; i++)
412         {
413                 table = (bc_locktrace_t*)lock_table.values[i];
414                 if(table->ptr == ptr)
415                 {
416                         if(table->is_owner)
417                         {
418                                 clear_table_entry(&lock_table, i, 1);
419                                 pthread_mutex_unlock(lock);
420                                 return;
421                         }
422                 }
423         }
425         pthread_mutex_unlock(lock);
429 void BC_Signals::unset_all_locks(void *ptr)
431         if(!global_signals) return;
432         pthread_mutex_lock(lock);
433 // Take off previous lock entry
434         for(int i = 0; i < lock_table.size; i++)
435         {
436                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
437                 if(table->ptr == ptr)
438                 {
439                         clear_table_entry(&lock_table, i, 1);
440                 }
441         }
442         pthread_mutex_unlock(lock);
446 void BC_Signals::enable_memory()
448         trace_memory = 1;
451 void BC_Signals::disable_memory()
453         trace_memory = 0;
457 void BC_Signals::set_buffer(int size, void *ptr, char* location)
459         if(!global_signals) return;
460         if(!trace_memory) return;
462 //printf("BC_Signals::set_buffer %p %s\n", ptr, location);
463         pthread_mutex_lock(lock);
464         append_table(&memory_table, new_bc_buffertrace(size, ptr, location));
465         pthread_mutex_unlock(lock);
468 int BC_Signals::unset_buffer(void *ptr)
470         if(!global_signals) return 0;
471         if(!trace_memory) return 0;
473         pthread_mutex_lock(lock);
474         for(int i = 0; i < memory_table.size; i++)
475         {
476                 if(((bc_buffertrace_t*)memory_table.values[i])->ptr == ptr)
477                 {
478 //printf("BC_Signals::unset_buffer %p\n", ptr);
479                         clear_table_entry(&memory_table, i, 1);
480                         pthread_mutex_unlock(lock);
481                         return 0;
482                 }
483         }
485         pthread_mutex_unlock(lock);
486 //      fprintf(stderr, "BC_Signals::unset_buffer buffer %p not found.\n", ptr);
487         return 1;
502 #ifdef TRACE_MEMORY
504 // void* operator new(size_t size) 
505 // {
506 // //printf("new 1 %d\n", size);
507 //     void *result = malloc(size);
508 //      BUFFER(size, result, "new");
509 // //printf("new 2 %d\n", size);
510 //      return result;
511 // }
512 // 
513 // void* operator new[](size_t size) 
514 // {
515 // //printf("new [] 1 %d\n", size);
516 //     void *result = malloc(size);
517 //      BUFFER(size, result, "new []");
518 // //printf("new [] 2 %d\n", size);
519 //      return result;
520 // }
521 // 
522 // void operator delete(void *ptr) 
523 // {
524 // //printf("delete 1 %p\n", ptr);
525 //      UNBUFFER(ptr);
526 // //printf("delete 2 %p\n", ptr);
527 //     free(ptr);
528 // }
529 // 
530 // void operator delete[](void *ptr) 
531 // {
532 // //printf("delete [] 1 %p\n", ptr);
533 //      UNBUFFER(ptr);
534 //     free(ptr);
535 // //printf("delete [] 2 %p\n", ptr);
536 // }
539 #endif