improve resize flash operation, fixup xv grab/ungrab, fixup label updates
[goodguy/history.git] / cinelerra-5.1 / guicast / bcsignals.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "bcwindowbase.h"
24 #include "bccmodels.h"
25 #include "bckeyboard.h"
26 #include "bcresources.h"
27
28 #include <ctype.h>
29 #include <dirent.h>
30 #include <execinfo.h>
31 #include <pwd.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37 #include <sys/ioctl.h>
38 #include <sys/prctl.h>
39 #include <sys/types.h>
40
41 BC_Signals* BC_Signals::global_signals = 0;
42 static int signal_done = 0;
43 static int table_id = 0;
44
45 static bc_locktrace_t* new_bc_locktrace(void *ptr,
46         const char *title,
47         const char *location)
48 {
49         bc_locktrace_t *result = (bc_locktrace_t*)malloc(sizeof(bc_locktrace_t));
50         result->ptr = ptr;
51         result->title = title;
52         result->location = location;
53         result->is_owner = 0;
54         result->id = table_id++;
55         result->tid = pthread_self();
56         return result;
57 }
58
59
60 static struct sigaction old_segv = {0, }, old_intr = {0, };
61 static void handle_dump(int n, siginfo_t * info, void *sc);
62
63 const char *BC_Signals::trap_path = 0;
64 void *BC_Signals::trap_data = 0;
65 void (*BC_Signals::trap_hook)(FILE *fp, void *data) = 0;
66 bool BC_Signals::trap_sigsegv = false;
67 bool BC_Signals::trap_sigintr = false;
68
69 static void uncatch_sig(int sig, struct sigaction &old)
70 {
71         struct sigaction act;
72         sigaction(sig, &old, &act);
73         old.sa_handler = 0;
74 }
75
76 static void catch_sig(int sig, struct sigaction &old)
77 {
78         struct sigaction act;
79         memset(&act, 0, sizeof(act));
80         act.sa_sigaction = handle_dump;
81         act.sa_flags = SA_SIGINFO;
82         sigaction(sig, &act, (!old.sa_handler ? &old : 0));
83 }
84
85 static void uncatch_intr() { uncatch_sig(SIGINT, old_intr); }
86 static void catch_intr() { catch_sig(SIGINT, old_intr); }
87 static void uncatch_segv() { uncatch_sig(SIGSEGV, old_segv); }
88 static void catch_segv() { catch_sig(SIGSEGV, old_segv); }
89
90 void BC_Signals::set_trap_path(const char *path)
91 {
92         trap_path = path;
93 }
94
95 void BC_Signals::set_trap_hook(void (*hook)(FILE *fp, void *vp), void *data)
96 {
97         trap_data = data;
98         trap_hook = hook;
99 }
100
101 void BC_Signals::set_catch_segv(bool v) {
102         if( v == trap_sigsegv ) return;
103         if( v ) catch_segv();
104         else uncatch_segv();
105         v = trap_sigsegv;
106 }
107
108 void BC_Signals::set_catch_intr(bool v) {
109         if( v == trap_sigintr ) return;
110         if( v ) catch_intr();
111         else uncatch_intr();
112         v = trap_sigintr;
113 }
114
115 typedef struct
116 {
117         int size;
118         void *ptr;
119         const char *location;
120 } bc_buffertrace_t;
121
122 static bc_buffertrace_t* new_bc_buffertrace(int size, void *ptr, const char *location)
123 {
124         bc_buffertrace_t *result = (bc_buffertrace_t*)malloc(sizeof(bc_buffertrace_t));
125         result->size = size;
126         result->ptr = ptr;
127         result->location = location;
128         return result;
129 }
130
131 static void bc_copy_textfile(int lines, FILE *ofp, const char *fmt,...)
132 {
133         va_list ap;    va_start(ap, fmt);
134         char bfr[BCTEXTLEN];  vsnprintf(bfr, sizeof(bfr), fmt, ap);
135         va_end(ap);
136         FILE *ifp = fopen(bfr,"r");
137         if( !ifp ) return;
138         while( --lines >= 0 && fgets(bfr,sizeof(bfr),ifp) ) fputs(bfr,ofp);
139         fclose(ifp);
140 }
141
142
143 // Need our own table to avoid recursion with the memory manager
144 typedef struct
145 {
146         void **values;
147         int size;
148         int allocation;
149 // This points to the next value to replace if the table wraps around
150         int current_value;
151 } bc_table_t;
152
153 static void* append_table(bc_table_t *table, void *ptr)
154 {
155         if(table->allocation <= table->size)
156         {
157                 if(table->allocation)
158                 {
159                         int new_allocation = table->allocation * 2;
160                         void **new_values = (void**)calloc(new_allocation, sizeof(void*));
161                         memcpy(new_values, table->values, sizeof(void*) * table->size);
162                         free(table->values);
163                         table->values = new_values;
164                         table->allocation = new_allocation;
165                 }
166                 else
167                 {
168                         table->allocation = 4096;
169                         table->values = (void**)calloc(table->allocation, sizeof(void*));
170                 }
171         }
172
173         table->values[table->size++] = ptr;
174         return ptr;
175 }
176
177 // Replace item in table pointed to by current_value and advance
178 // current_value
179 static void* overwrite_table(bc_table_t *table, void *ptr)
180 {
181         free(table->values[table->current_value]);
182         table->values[table->current_value++] = ptr;
183         if(table->current_value >= table->size) table->current_value = 0;
184         return 0;
185 }
186
187 static void clear_table(bc_table_t *table, int delete_objects)
188 {
189         if(delete_objects)
190         {
191                 for(int i = 0; i < table->size; i++)
192                 {
193                         free(table->values[i]);
194                 }
195         }
196         table->size = 0;
197 }
198
199 static void clear_table_entry(bc_table_t *table, int number, int delete_object)
200 {
201         if(delete_object) free(table->values[number]);
202         for(int i = number; i < table->size - 1; i++)
203         {
204                 table->values[i] = table->values[i + 1];
205         }
206         table->size--;
207 }
208
209 // Table of functions currently running.
210 static bc_table_t execution_table = { 0, 0, 0, 0 };
211
212 // Table of locked positions
213 static bc_table_t lock_table = { 0, 0, 0, 0 };
214
215 // Table of buffers
216 static bc_table_t memory_table = { 0, 0, 0, 0 };
217
218 static bc_table_t temp_files = { 0, 0, 0, 0 };
219
220 // Can't use Mutex because it would be recursive
221 static pthread_mutex_t *lock = 0;
222 static pthread_mutex_t *handler_lock = 0;
223 // incase lock set after task ends
224 static pthread_t last_lock_thread = 0;
225 static const char *last_lock_title = 0;
226 static const char *last_lock_location = 0;
227 // Don't trace memory until this is true to avoid initialization
228 static int trace_memory = 0;
229
230
231 static const char* signal_titles[] =
232 {
233         "NULL",
234         "SIGHUP",
235         "SIGINT",
236         "SIGQUIT",
237         "SIGILL",
238         "SIGTRAP",
239         "SIGABRT",
240         "SIGBUS",
241         "SIGFPE",
242         "SIGKILL",
243         "SIGUSR1",
244         "SIGSEGV",
245         "SIGUSR2",
246         "SIGPIPE",
247         "SIGALRM",
248         "SIGTERM"
249 };
250
251 void BC_Signals::dump_stack(FILE *fp)
252 {
253         void *buffer[256];
254         int total = backtrace (buffer, 256);
255         char **result = backtrace_symbols (buffer, total);
256         fprintf(fp, "BC_Signals::dump_stack\n");
257         for(int i = 0; i < total; i++)
258         {
259                 fprintf(fp, "%s\n", result[i]);
260         }
261 }
262
263 // Kill subprocesses
264 void BC_Signals::kill_subs()
265 {
266 // List /proc directory
267         DIR *dirstream;
268         struct dirent64 *new_filename;
269         struct stat ostat;
270         char path[BCTEXTLEN];
271         char string[BCTEXTLEN];
272
273         dirstream = opendir("/proc");
274         if(!dirstream) return;
275
276         while( (new_filename = readdir64(dirstream)) != 0 )
277         {
278 // All digits are numbers
279                 char *ptr = new_filename->d_name;
280                 int got_alpha = 0;
281                 while(*ptr)
282                 {
283                         if(*ptr == '.' || isalpha(*ptr++))
284                         {
285                                 got_alpha = 1;
286                                 break;
287                         }
288                 }
289
290                 if(got_alpha) continue;
291
292 // Must be a directory
293                 sprintf(path, "/proc/%s", new_filename->d_name);
294                 if(!stat(path, &ostat))
295                 {
296                         if(S_ISDIR(ostat.st_mode))
297                         {
298 // Read process stat
299                                 strcat(path, "/stat");
300 //printf("kill_subs %d %s\n", __LINE__, path);
301                                 FILE *fd = fopen(path, "r");
302
303 // Must search forwards because the file is 0 length
304                                 if(fd)
305                                 {
306                                         while(!feof(fd))
307                                         {
308                                                 char c = fgetc(fd);
309 //printf("kill_subs %d %d\n", __LINE__, c);
310                                                 if(c == ')')
311                                                 {
312 // Search for 2 spaces
313                                                         int spaces = 0;
314                                                         while(!feof(fd) && spaces < 2)
315                                                         {
316                                                                 c = fgetc(fd);
317                                                                 if(c == ' ')
318                                                                         spaces++;
319                                                         }
320
321 // Read in parent process
322                                                         ptr = string;
323                                                         while(!feof(fd))
324                                                         {
325                                                                 *ptr = fgetc(fd);
326                                                                 if(*ptr == ' ')
327                                                                 {
328                                                                         *ptr = 0;
329                                                                         break;
330                                                                 }
331                                                                 ptr++;
332                                                         }
333
334 // printf("kill_subs %d process=%d getpid=%d parent_process=%d\n",
335 // __LINE__,
336 // atoi(new_filename->d_name),
337 // getpid(),
338 // atoi(string));
339                                                         int parent_process = atoi(string);
340                                                         int child_process = atoi(new_filename->d_name);
341
342 // Kill if we're the parent
343                                                         if(getpid() == parent_process)
344                                                         {
345 //printf("kill_subs %d: process=%d\n", __LINE__, atoi(new_filename->d_name));
346                                                                 kill(child_process, SIGKILL);
347                                                         }
348                                                 }
349                                         }
350
351                                         fclose(fd);
352                                 }
353                         }
354                 }
355         }
356 }
357
358 static void signal_entry(int signum)
359 {
360         signal(signum, SIG_DFL);
361
362         pthread_mutex_lock(handler_lock);
363         if(signal_done)
364         {
365                 pthread_mutex_unlock(handler_lock);
366                 exit(0);
367         }
368
369         signal_done = 1;
370         pthread_mutex_unlock(handler_lock);
371
372
373         printf("signal_entry: got %s my pid=%d execution table size=%d:\n",
374                 signal_titles[signum],
375                 getpid(),
376                 execution_table.size);
377
378         BC_Signals::kill_subs();
379         BC_Signals::dump_traces();
380         BC_Signals::dump_locks();
381         BC_Signals::dump_buffers();
382         BC_Signals::delete_temps();
383
384 // Call user defined signal handler
385         BC_Signals::global_signals->signal_handler(signum);
386
387         abort();
388 }
389
390 static void signal_entry_recoverable(int signum)
391 {
392         printf("signal_entry_recoverable: got %s my pid=%d\n",
393                 signal_titles[signum],
394                 getpid());
395 }
396
397 // used to terminate child processes when program terminates
398 static void handle_exit(int signum)
399 {
400 //printf("child %d exit\n", getpid());
401         exit(0);
402 }
403
404 void BC_Signals::set_sighup_exit(int enable)
405 {
406         if( enable ) {
407 // causes SIGHUP to be generated when parent dies
408                 signal(SIGHUP, handle_exit);
409                 prctl(PR_SET_PDEATHSIG, SIGHUP, 0,0,0);
410 // prevents ^C from signalling child when attached to gdb
411                 setpgid(0, 0);
412                 if( isatty(0) ) ioctl(0, TIOCNOTTY, 0);
413         }
414         else {
415                 signal(SIGHUP, signal_entry);
416                 prctl(PR_SET_PDEATHSIG, 0,0,0,0);
417         }
418 }
419
420 BC_Signals::BC_Signals()
421 {
422 }
423 BC_Signals::~BC_Signals()
424 {
425   BC_CModels::bcxfer_stop_slicers();
426 }
427
428 void BC_Signals::dump_traces(FILE *fp)
429 {
430 // Dump trace table
431         if(execution_table.size)
432         {
433                 for(int i = execution_table.current_value; i < execution_table.size; i++)
434                         fprintf(fp,"    %s\n", (char*)execution_table.values[i]);
435                 for(int i = 0; i < execution_table.current_value; i++)
436                         fprintf(fp,"    %s\n", (char*)execution_table.values[i]);
437         }
438
439 }
440
441 void BC_Signals::dump_locks(FILE *fp)
442 {
443 // Dump lock table
444 #ifdef TRACE_LOCKS
445         fprintf(fp,"signal_entry: lock table size=%d\n", lock_table.size);
446         for(int i = 0; i < lock_table.size; i++)
447         {
448                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
449                 fprintf(fp,"    %p %s %s %p%s\n", table->ptr,
450                         table->title, table->location, (void*)table->tid,
451                         table->is_owner ? " *" : "");
452         }
453 #endif
454 }
455
456 void BC_Signals::dump_buffers(FILE *fp)
457 {
458 #ifdef TRACE_MEMORY
459         pthread_mutex_lock(lock);
460 // Dump buffer table
461         fprintf(fp,"BC_Signals::dump_buffers: buffer table size=%d\n", memory_table.size);
462         for(int i = 0; i < memory_table.size; i++)
463         {
464                 bc_buffertrace_t *entry = (bc_buffertrace_t*)memory_table.values[i];
465                 fprintf(fp,"    %d %p %s\n", entry->size, entry->ptr, entry->location);
466         }
467         pthread_mutex_unlock(lock);
468 #endif
469 }
470
471 void BC_Signals::delete_temps()
472 {
473         pthread_mutex_lock(lock);
474         if(temp_files.size) printf("BC_Signals::delete_temps: deleting %d temp files\n", temp_files.size);
475         for(int i = 0; i < temp_files.size; i++)
476         {
477                 printf("    %s\n", (char*)temp_files.values[i]);
478                 remove((char*)temp_files.values[i]);
479         }
480         pthread_mutex_unlock(lock);
481 }
482
483 void BC_Signals::reset_locks()
484 {
485         pthread_mutex_unlock(lock);
486 }
487
488 void BC_Signals::set_temp(char *string)
489 {
490         char *new_string = strdup(string);
491         append_table(&temp_files, new_string);
492 }
493
494 void BC_Signals::unset_temp(char *string)
495 {
496         for(int i = 0; i < temp_files.size; i++)
497         {
498                 if(!strcmp((char*)temp_files.values[i], string))
499                 {
500                         clear_table_entry(&temp_files, i, 1);
501                         break;
502                 }
503         }
504 }
505
506
507 int BC_Signals::x_error_handler(Display *display, XErrorEvent *event)
508 {
509         char string[1024];
510         XGetErrorText(event->display, event->error_code, string, 1024);
511         fprintf(stderr, "BC_Signals::x_error_handler: error_code=%d opcode=%d,%d id=0x%jx %s\n",
512                 event->error_code, event->request_code, event->minor_code, event->resourceid, string);
513         return 0;
514 }
515
516
517 void BC_Signals::initialize()
518 {
519         BC_Signals::global_signals = this;
520         lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
521         handler_lock = (pthread_mutex_t*)calloc(1, sizeof(pthread_mutex_t));
522         pthread_mutex_init(lock, 0);
523         pthread_mutex_init(handler_lock, 0);
524         old_err_handler = XSetErrorHandler(x_error_handler);
525         initialize2();
526 }
527
528 void BC_Signals::terminate()
529 {
530         BC_Signals::global_signals = 0;
531         uncatch_segv();  uncatch_intr();
532         signal(SIGHUP, SIG_DFL);
533         signal(SIGINT, SIG_DFL);
534         signal(SIGQUIT, SIG_DFL);
535         signal(SIGTERM, SIG_DFL);
536         signal(SIGFPE, SIG_DFL);
537         signal(SIGPIPE, SIG_DFL);
538         signal(SIGUSR2, SIG_DFL);
539         XSetErrorHandler(old_err_handler);
540 }
541
542 // callable from debugger
543 extern "C"
544 void dump()
545 {
546         BC_Signals::dump_traces();
547         BC_Signals::dump_locks();
548         BC_Signals::dump_buffers();
549 }
550
551 // kill SIGUSR2
552 void BC_Signals::signal_dump(int signum)
553 {
554         BC_KeyboardHandler::kill_grabs();
555         dump();
556         signal(SIGUSR2, signal_dump);
557 }
558
559
560
561
562
563
564 void BC_Signals::initialize2()
565 {
566         signal(SIGHUP, signal_entry);
567         signal(SIGINT, signal_entry);
568         signal(SIGQUIT, signal_entry);
569         // SIGKILL cannot be stopped
570         // signal(SIGKILL, signal_entry);
571         catch_segv();
572         signal(SIGTERM, signal_entry);
573         signal(SIGFPE, signal_entry);
574         signal(SIGPIPE, signal_entry_recoverable);
575         signal(SIGUSR2, signal_dump);
576 }
577
578
579 void BC_Signals::signal_handler(int signum)
580 {
581 printf("BC_Signals::signal_handler\n");
582 //      exit(0);
583 }
584
585 const char* BC_Signals::sig_to_str(int number)
586 {
587         return signal_titles[number];
588 }
589
590 #define TOTAL_TRACES 16
591
592 void BC_Signals::new_trace(const char *text)
593 {
594         if(!global_signals) return;
595         pthread_mutex_lock(lock);
596
597 // Wrap around
598         if(execution_table.size >= TOTAL_TRACES)
599         {
600                 overwrite_table(&execution_table, strdup(text));
601 //              clear_table(&execution_table, 1);
602         }
603         else
604         {
605                 append_table(&execution_table, strdup(text));
606         }
607         pthread_mutex_unlock(lock);
608 }
609
610 void BC_Signals::new_trace(const char *file, const char *function, int line)
611 {
612         char string[BCTEXTLEN];
613         snprintf(string, BCTEXTLEN, "%s: %s: %d", file, function, line);
614         new_trace(string);
615 }
616
617 void BC_Signals::delete_traces()
618 {
619         if(!global_signals) return;
620         pthread_mutex_lock(lock);
621         clear_table(&execution_table, 0);
622         pthread_mutex_unlock(lock);
623 }
624
625 // no canceling with lock held
626 void BC_Signals::lock_locks(const char *s)
627 {
628         pthread_mutex_lock(lock);
629         last_lock_thread = pthread_self();
630         last_lock_title = s;
631         last_lock_location = 0;
632 }
633
634 void BC_Signals::unlock_locks()
635 {
636         pthread_mutex_unlock(lock);
637 }
638
639 #define TOTAL_LOCKS 256
640
641 int BC_Signals::set_lock(void *ptr,
642         const char *title,
643         const char *location)
644 {
645         if(!global_signals) return 0;
646         bc_locktrace_t *table = 0;
647         int id_return = 0;
648
649         pthread_mutex_lock(lock);
650         last_lock_thread = pthread_self();
651         last_lock_title = title;
652         last_lock_location = location;
653         if(lock_table.size >= TOTAL_LOCKS)
654                 clear_table(&lock_table, 0);
655
656 // Put new lock entry
657         table = new_bc_locktrace(ptr, title, location);
658         append_table(&lock_table, table);
659         id_return = table->id;
660
661         pthread_mutex_unlock(lock);
662         return id_return;
663 }
664
665 void BC_Signals::set_lock2(int table_id)
666 {
667         if(!global_signals) return;
668
669         bc_locktrace_t *table = 0;
670         pthread_mutex_lock(lock);
671         for(int i = lock_table.size - 1; i >= 0; i--)
672         {
673                 table = (bc_locktrace_t*)lock_table.values[i];
674 // Got it.  Hasn't been unlocked/deleted yet.
675                 if(table->id == table_id)
676                 {
677                         table->is_owner = 1;
678                         table->tid = pthread_self();
679                         pthread_mutex_unlock(lock);
680                         return;
681                 }
682         }
683         pthread_mutex_unlock(lock);
684 }
685
686 void BC_Signals::unset_lock2(int table_id)
687 {
688         if(!global_signals) return;
689
690         bc_locktrace_t *table = 0;
691         pthread_mutex_lock(lock);
692         for(int i = lock_table.size - 1; i >= 0; i--)
693         {
694                 table = (bc_locktrace_t*)lock_table.values[i];
695                 if(table->id == table_id)
696                 {
697                         clear_table_entry(&lock_table, i, 1);
698                         break;
699                 }
700         }
701         pthread_mutex_unlock(lock);
702 }
703
704 void BC_Signals::unset_lock(void *ptr)
705 {
706         if(!global_signals) return;
707
708         bc_locktrace_t *table = 0;
709         pthread_mutex_lock(lock);
710
711 // Take off currently held entry
712         for(int i = 0; i < lock_table.size; i++)
713         {
714                 table = (bc_locktrace_t*)lock_table.values[i];
715                 if(table->ptr == ptr)
716                 {
717                         if(table->is_owner)
718                         {
719                                 clear_table_entry(&lock_table, i, 1);
720                                 break;
721                         }
722                 }
723         }
724
725         pthread_mutex_unlock(lock);
726 }
727
728
729 void BC_Signals::unset_all_locks(void *ptr)
730 {
731         if(!global_signals) return;
732         pthread_mutex_lock(lock);
733 // Take off previous lock entry
734         for(int i = 0; i < lock_table.size; )
735         {
736                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
737                 if(table->ptr == ptr)
738                 {
739                         clear_table_entry(&lock_table, i, 1);
740                         continue;
741                 }
742                 ++i;
743         }
744         pthread_mutex_unlock(lock);
745 }
746
747 void BC_Signals::clear_locks_tid(pthread_t tid)
748 {
749         if(!global_signals) return;
750         pthread_mutex_lock(lock);
751 // Take off previous lock entry
752         for(int i = 0; i < lock_table.size; )
753         {
754                 bc_locktrace_t *table = (bc_locktrace_t*)lock_table.values[i];
755                 if(table->tid == tid)
756                 {
757                         clear_table_entry(&lock_table, i, 1);
758                         continue;
759                 }
760                 ++i;
761         }
762         pthread_mutex_unlock(lock);
763 }
764
765
766 void BC_Signals::enable_memory()
767 {
768         trace_memory = 1;
769 }
770
771 void BC_Signals::disable_memory()
772 {
773         trace_memory = 0;
774 }
775
776
777 void BC_Signals::set_buffer(int size, void *ptr, const char* location)
778 {
779         if(!global_signals) return;
780         if(!trace_memory) return;
781
782 //printf("BC_Signals::set_buffer %p %s\n", ptr, location);
783         pthread_mutex_lock(lock);
784         append_table(&memory_table, new_bc_buffertrace(size, ptr, location));
785         pthread_mutex_unlock(lock);
786 }
787
788 int BC_Signals::unset_buffer(void *ptr)
789 {
790         if(!global_signals) return 0;
791         if(!trace_memory) return 0;
792
793         int ret = 1;
794         pthread_mutex_lock(lock);
795         for(int i = 0; i < memory_table.size; i++)
796         {
797                 if(((bc_buffertrace_t*)memory_table.values[i])->ptr == ptr)
798                 {
799 //printf("BC_Signals::unset_buffer %p\n", ptr);
800                         clear_table_entry(&memory_table, i, 1);
801                         ret = 0;
802                         break;
803                 }
804         }
805
806         pthread_mutex_unlock(lock);
807 //      fprintf(stderr, "BC_Signals::unset_buffer buffer %p not found.\n", ptr);
808         return ret;
809 }
810
811
812 #include <ucontext.h>
813 #include <sys/wait.h>
814 #include "thread.h"
815
816 #if __i386__
817 #define IP eip
818 #endif
819 #if __x86_64__
820 #define IP rip
821 #endif
822 #ifndef IP
823 #error gotta have IP
824 #endif
825
826
827 static void handle_dump(int n, siginfo_t * info, void *sc)
828 {
829         uncatch_segv();  uncatch_intr();
830         signal(SIGSEGV, SIG_DFL);
831         signal(SIGINT, SIG_DFL);
832         // gotta be root, or the dump is worthless
833         int uid = getuid();
834         if( uid != 0 ) return;
835         ucontext_t *uc = (ucontext_t *)sc;
836         int pid = getpid(), tid = gettid();
837         struct sigcontext *c = (struct sigcontext *)&uc->uc_mcontext;
838         fprintf(stderr,"** %s at %p in pid %d, tid %d\n",
839                 n==SIGSEGV? "segv" : n==SIGINT? "intr" : "trap",
840                 (void*)c->IP, pid, tid);
841         FILE *fp = 0;
842         char fn[PATH_MAX];
843         if( BC_Signals::trap_path ) {
844                 snprintf(fn, sizeof(fn), BC_Signals::trap_path, pid);
845                 fp = fopen(fn,"w");
846         }
847         if( fp ) {
848                 fprintf(stderr,"writing debug data to %s\n", fn);
849                 fprintf(fp,"** %s at %p in pid %d, tid %d\n",
850                         n==SIGSEGV? "segv" : n==SIGINT? "intr" : "trap",
851                         (void*)c->IP, pid, tid);
852         }
853         else {
854                 strcpy(fn, "stdout");
855                 fp = stdout;
856         }
857         time_t t;  time(&t);
858         fprintf(fp,"created on %s", ctime(&t));
859         struct passwd *pw = getpwuid(uid);
860         if( pw ) {
861                 fprintf(fp,"        by %d:%d %s(%s)\n",
862                         pw->pw_uid, pw->pw_gid, pw->pw_name, pw->pw_gecos);
863         }
864         fprintf(fp,"\nCPUS: %d\n",   BC_Resources::get_machine_cpus());
865         fprintf(fp,"\nCPUINFO:\n");  bc_copy_textfile(32, fp,"/proc/cpuinfo");
866         fprintf(fp,"\nTHREADS:\n");  Thread::dump_threads(fp);
867         fprintf(fp,"\nTRACES:\n");   BC_Signals::dump_traces(fp);
868         fprintf(fp,"\nLOCKS:\n");    BC_Signals::dump_locks(fp);
869         fprintf(fp,"\nBUFFERS:\n");  BC_Signals::dump_buffers(fp);
870         if( BC_Signals::trap_hook ) {
871                 fprintf(fp,"\nMAIN HOOK:\n");
872                 BC_Signals::trap_hook(fp, BC_Signals::trap_data);
873         }
874         fprintf(fp,"\nVERSION:\n");  bc_copy_textfile(INT_MAX, fp,"/proc/version");
875         fprintf(fp,"\nMEMINFO:\n");  bc_copy_textfile(INT_MAX, fp,"/proc/meminfo");
876         fprintf(fp,"\nMAPS:\n");     bc_copy_textfile(INT_MAX, fp,"/proc/%d/maps",pid);
877         fprintf(fp,"\n\n");
878         if( fp != stdout ) fclose(fp);
879         char cmd[1024], *cp = cmd;
880         cp += sprintf(cp, "exec gdb /proc/%d/exe -p %d --batch --quiet "
881                 "-ex \"thread apply all info registers\" "
882                 "-ex \"thread apply all bt full\" "
883                 "-ex \"quit\"", pid, pid);
884         if( fp != stdout )
885                 cp += sprintf(cp," >> \"%s\"", fn);
886         cp += sprintf(cp," 2>&1");
887 //printf("handle_dump:: pid=%d, cmd='%s'  fn='%s'\n",pid,cmd,fn);
888         pid = vfork();
889         if( pid < 0 ) {
890                 fprintf(stderr,"** can't start gdb, dump abondoned\n");
891                 return;
892         }
893         if( pid > 0 ) {
894                 waitpid(pid,0,0);
895                 fprintf(stderr,"** dump complete\n");
896                 return;
897         }
898         char *const argv[4] = { (char*) "/bin/sh", (char*) "-c", cmd, 0 };
899         execvp(argv[0], &argv[0]);
900 }
901
902
903
904
905
906 #ifdef TRACE_MEMORY
907
908 // void* operator new(size_t size)
909 // {
910 // //printf("new 1 %d\n", size);
911 //     void *result = malloc(size);
912 //      BUFFER(size, result, "new");
913 // //printf("new 2 %d\n", size);
914 //      return result;
915 // }
916 //
917 // void* operator new[](size_t size)
918 // {
919 // //printf("new [] 1 %d\n", size);
920 //     void *result = malloc(size);
921 //      BUFFER(size, result, "new []");
922 // //printf("new [] 2 %d\n", size);
923 //      return result;
924 // }
925 //
926 // void operator delete(void *ptr)
927 // {
928 // //printf("delete 1 %p\n", ptr);
929 //      UNBUFFER(ptr);
930 // //printf("delete 2 %p\n", ptr);
931 //     free(ptr);
932 // }
933 //
934 // void operator delete[](void *ptr)
935 // {
936 // //printf("delete [] 1 %p\n", ptr);
937 //      UNBUFFER(ptr);
938 //     free(ptr);
939 // //printf("delete [] 2 %p\n", ptr);
940 // }
941
942
943 #endif