1 /*
2 * Copyright (c) 2016-2018 NLNet Labs.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif
30 #ifndef _GNU_SOURCE
31 #define __USE_GNU
32 #endif
33
34 #include "config.h"
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <stdint.h>
40 #include <unistd.h>
41 #include <signal.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <sys/time.h>
45 #include <sys/resource.h>
46 #include <dlfcn.h>
47 #include <pthread.h>
48 #ifdef HAVE_BACKTRACE_FULL
49 #include <backtrace.h>
50 #endif
51 #ifdef HAVE_BACKTRACE
52 #include <execinfo.h>
53 #endif
54 #ifdef HAVE_LIBUNWIND
55 #include <libunwind.h>
56 #endif
57
58 #include "janitor.h"
59
60 static struct sigaction original_quit_action;
61 static struct sigaction original_abrt_action;
62 static struct sigaction original_segv_action;
63 static struct sigaction original_fpe_action;
64 static struct sigaction original_ill_action;
65 static struct sigaction original_bus_action;
66 static struct sigaction original_sys_action;
67
68 static janitor_alertfn_t alert;
69 static janitor_alertfn_t report;
70
71 struct janitor_threadclass_struct {
72 char* name;
73 int detached;
74 int autorun;
75 int blocksignals;
76 int hasattr;
77 pthread_attr_t attr;
78 };
79
80 int
janitor_threadclass_create(janitor_threadclass_t * threadclass,const char * name)81 janitor_threadclass_create(janitor_threadclass_t* threadclass, const char* name)
82 {
83 *threadclass = malloc(sizeof(struct janitor_threadclass_struct));
84 (*threadclass)->name = strdup(name);
85 (*threadclass)->detached = 0;
86 (*threadclass)->autorun = 0;
87 (*threadclass)->blocksignals = 0;
88 (*threadclass)->hasattr = 0;
89 return 0;
90 }
91
92 char*
janitor_threadclass_name(janitor_threadclass_t threadclass)93 janitor_threadclass_name(janitor_threadclass_t threadclass)
94 {
95 return threadclass->name;
96 }
97
98 void
janitor_threadclass_destroy(janitor_threadclass_t threadclass)99 janitor_threadclass_destroy(janitor_threadclass_t threadclass)
100 {
101 if (threadclass->hasattr) {
102 pthread_attr_destroy(&threadclass->attr);
103 }
104 free(threadclass->name);
105 free(threadclass);
106 }
107
108 void
janitor_threadclass_setdetached(janitor_threadclass_t threadclass)109 janitor_threadclass_setdetached(janitor_threadclass_t threadclass)
110 {
111 threadclass->detached = 1;
112 if (!threadclass->hasattr) {
113 pthread_attr_init(&threadclass->attr);
114 }
115 pthread_attr_setdetachstate(&threadclass->attr, PTHREAD_CREATE_DETACHED);
116 }
117
118 void
janitor_threadclass_setautorun(janitor_threadclass_t threadclass)119 janitor_threadclass_setautorun(janitor_threadclass_t threadclass)
120 {
121 threadclass->autorun = 1;
122 }
123
124 void
janitor_threadclass_setblockedsignals(janitor_threadclass_t threadclass)125 janitor_threadclass_setblockedsignals(janitor_threadclass_t threadclass)
126 {
127 threadclass->blocksignals = 1;
128 }
129
130 void
janitor_threadclass_setminstacksize(janitor_threadclass_t threadclass,size_t minstacksize)131 janitor_threadclass_setminstacksize(janitor_threadclass_t threadclass, size_t minstacksize)
132 {
133 size_t stacksize;
134 if (!threadclass->hasattr) {
135 pthread_attr_init(&threadclass->attr);
136 }
137 pthread_attr_getstacksize(&threadclass->attr, &stacksize);
138 if (stacksize < minstacksize) {
139 pthread_attr_setstacksize(&threadclass->attr, minstacksize);
140 threadclass->hasattr = 1;
141 }
142 }
143
144 static void fail(const char* file, int line, const char* func, const char* expr, int stat);
145 #define CHECKFAIL(EX) do { int CHECKFAIL; if((CHECKFAIL = (EX))) { fail(__FILE__,__LINE__,__func__,#EX,CHECKFAIL); goto fail; } } while(0)
146
147 static void
fail(const char * file,int line,const char * func,const char * expr,int stat)148 fail(const char* file, int line, const char* func, const char* expr, int stat)
149 {
150 report("Failure %d in %s at %s:%d of %s\n", stat, func, file, line, expr);
151 }
152
153 void
janitor_initialize(janitor_alertfn_t alertfn,janitor_alertfn_t reportfn)154 janitor_initialize(janitor_alertfn_t alertfn, janitor_alertfn_t reportfn)
155 {
156 report = reportfn;
157 alert = alertfn;
158 }
159
160 struct janitor_thread_struct {
161 struct janitor_thread_struct* next;
162 struct janitor_thread_struct* prev;
163 pthread_t thread;
164 janitor_runfn_t runfunc;
165 void* rundata;
166 int isstarted;
167 int blocksignals;
168 pthread_barrier_t startbarrier;
169 janitor_threadclass_t threadclass;
170 };
171
172 static pthread_mutex_t threadlock = PTHREAD_MUTEX_INITIALIZER;
173 static struct janitor_thread_struct *threadlist = NULL; /* running threads */
174 static struct janitor_thread_struct *finishedthreadlist = NULL; /* threads waiting to be joined */
175 static pthread_once_t threadlocatorinitializeonce = PTHREAD_ONCE_INIT;
176 static pthread_key_t threadlocator;
177 static pthread_cond_t threadblock = PTHREAD_COND_INITIALIZER;
178
179 static void
threadlocatorinitialize(void)180 threadlocatorinitialize(void)
181 {
182 pthread_key_create(&threadlocator, NULL);
183 }
184
185 static void
janitor_thread_unregister(janitor_thread_t info)186 janitor_thread_unregister(janitor_thread_t info)
187 {
188 int err, errcount;
189 if (info == NULL)
190 return;
191 CHECKFAIL(pthread_mutex_lock(&threadlock));
192 if (threadlist != NULL) {
193 if (threadlist == info) {
194 if (info->next == info) {
195 threadlist = NULL;
196 } else {
197 threadlist = info->next;
198 }
199 }
200 info->next->prev = info->prev;
201 info->prev->next = info->next;
202 info->next = info->prev = NULL;
203 /* The implementation on FreeBSD10 of pthreads is pretty brain dead.
204 * If two threads enter a barrier with count 2, then the barrier
205 * is satisfied and thus not really being waited upon. If now one
206 * of the threads tries to destroy the thread, while the other thread
207 * did not have its turn yet on the CPU, then still the destroy call
208 * will return EBUSY. Although valid, this is really a brain dead
209 * implementation causing pain to application developers to do the
210 * following every time:
211 */
212 errcount = 0;
213 do {
214 err = pthread_barrier_destroy(&info->startbarrier);
215 if (err == EBUSY) {
216 ++errcount;
217 sleep(1);
218 }
219 } while(err == EBUSY && errcount <= 3);
220 CHECKFAIL(pthread_cond_signal(&threadblock));
221 }
222 CHECKFAIL(pthread_mutex_unlock(&threadlock));
223 fail:
224 ;
225 }
226
227 static void
janitor_thread_dispose(janitor_thread_t info)228 janitor_thread_dispose(janitor_thread_t info)
229 {
230 if (info == NULL)
231 return;
232 if (!info->threadclass || !info->threadclass->detached) {
233 pthread_mutex_lock(&threadlock);
234 if (finishedthreadlist != NULL) {
235 if (finishedthreadlist == info) {
236 if (info->next == info) {
237 finishedthreadlist = NULL;
238 } else {
239 finishedthreadlist = info->next;
240 }
241 }
242 if(info->next && info->next->prev == info)
243 info->next->prev = info->prev;
244 if(info->prev && info->prev->next == info)
245 info->prev->next = info->next;
246 info->next = info->prev = NULL;
247 }
248 pthread_mutex_unlock(&threadlock);
249 }
250 free(info);
251 }
252
253 static void
janitor_thread_register(janitor_thread_t info)254 janitor_thread_register(janitor_thread_t info)
255 {
256 pthread_mutex_lock(&threadlock);
257 pthread_once(&threadlocatorinitializeonce, threadlocatorinitialize);
258 if (threadlist != NULL) {
259 info->next = threadlist;
260 info->prev = threadlist->prev;
261 threadlist->prev->next = info;
262 threadlist->prev = info;
263 } else {
264 info->next = info->prev = info;
265 }
266 threadlist = info;
267 pthread_mutex_unlock(&threadlock);
268 }
269
270 static void
janitor_thread_finished(janitor_thread_t info)271 janitor_thread_finished(janitor_thread_t info)
272 {
273 if (!info->threadclass->detached) {
274 pthread_mutex_lock(&threadlock);
275 if (finishedthreadlist != NULL) {
276 info->next = finishedthreadlist;
277 info->prev = finishedthreadlist->prev;
278 finishedthreadlist->prev->next = info;
279 finishedthreadlist->prev = info;
280 } else {
281 info->next = info->prev = info;
282 }
283 finishedthreadlist = info;
284 pthread_mutex_unlock(&threadlock);
285 } else {
286 pthread_detach(pthread_self());
287 janitor_thread_dispose(info);
288 }
289 }
290
291 static void*
runthread(void * data)292 runthread(void* data)
293 {
294 int err;
295 sigset_t sigset;
296 struct janitor_thread_struct* info;
297 stack_t ss;
298 stack_t prevss;
299 info = (struct janitor_thread_struct*) data;
300 pthread_setspecific(threadlocator, info);
301 ss.ss_sp = malloc(SIGSTKSZ);
302 ss.ss_size = SIGSTKSZ;
303 ss.ss_flags = 0;
304 sigaltstack(&ss, &prevss);
305 pthread_barrier_wait(&info->startbarrier);
306 if (info->blocksignals) {
307 sigfillset(&sigset);
308 sigdelset(&sigset, SIGQUIT);
309 sigdelset(&sigset, SIGABRT);
310 sigdelset(&sigset, SIGSEGV);
311 sigdelset(&sigset, SIGFPE);
312 sigdelset(&sigset, SIGILL);
313 sigdelset(&sigset, SIGBUS);
314 sigdelset(&sigset, SIGSYS);
315 if ((err = pthread_sigmask(SIG_SETMASK, &sigset, NULL)))
316 report("pthread_sigmask: %s (%d)", strerror(err), err);
317 }
318 info->runfunc(info->rundata);
319 sigaltstack(&prevss, NULL);
320 free(ss.ss_sp); /* libxml has/had problems when freeing this as it tries to access it */
321 janitor_thread_unregister(info);
322 janitor_thread_finished(info);
323 return NULL;
324 }
325
326 int
janitor_thread_create(janitor_thread_t * thread,janitor_threadclass_t threadclass,janitor_runfn_t func,void * data)327 janitor_thread_create(janitor_thread_t* thread, janitor_threadclass_t threadclass, janitor_runfn_t func, void*data)
328 {
329 struct janitor_thread_struct* info;
330 info = malloc(sizeof (struct janitor_thread_struct));
331 info->runfunc = func;
332 info->rundata = data;
333 info->blocksignals = 0;
334 info->isstarted = 0;
335 info->threadclass = threadclass;
336 CHECKFAIL(pthread_barrier_init(&info->startbarrier, NULL, 2));
337 CHECKFAIL(pthread_create(&info->thread, ((threadclass && threadclass->hasattr) ? &threadclass->attr : NULL), runthread, info));
338 janitor_thread_register(info);
339 *thread = info;
340 if(threadclass && threadclass->autorun) {
341 janitor_thread_start(info);
342 }
343 return 0;
344 fail:
345 return 1;
346 }
347
janitor_thread_signal(janitor_thread_t thread)348 void janitor_thread_signal(janitor_thread_t thread)
349 {
350 pthread_kill(thread->thread, SIGHUP);
351 }
352
353 void
janitor_thread_start(janitor_thread_t thread)354 janitor_thread_start(janitor_thread_t thread)
355 {
356 int isstarted;
357
358 pthread_mutex_lock(&threadlock);
359 isstarted = thread->isstarted;
360 thread->isstarted = 1;
361 pthread_mutex_unlock(&threadlock);
362
363 if (!isstarted) {
364 pthread_barrier_wait(&thread->startbarrier);
365 }
366 }
367
368 int
janitor_thread_join(janitor_thread_t thread)369 janitor_thread_join(janitor_thread_t thread)
370 {
371 janitor_thread_t info;
372 int status;
373 status = pthread_join(thread->thread, NULL);
374 janitor_thread_dispose(thread);
375 return status;
376 }
377
378 int
janitor_thread_tryjoinall(janitor_threadclass_t threadclass)379 janitor_thread_tryjoinall(janitor_threadclass_t threadclass)
380 {
381 struct janitor_thread_struct* thread;
382 struct janitor_thread_struct* foundthread;
383
384 do {
385 foundthread = NULL;
386 pthread_mutex_lock(&threadlock);
387 thread = finishedthreadlist;
388 if (thread) {
389 do {
390 if (thread->threadclass == threadclass) {
391 foundthread = thread;
392 break;
393 }
394 thread = thread->next;
395 } while (thread != finishedthreadlist);
396 }
397 pthread_mutex_unlock(&threadlock);
398 if (foundthread) {
399 janitor_thread_join(foundthread);
400 }
401 } while(foundthread);
402
403 pthread_mutex_lock(&threadlock);
404 foundthread = NULL;
405 thread = finishedthreadlist;
406 if (thread) {
407 do {
408 if (thread->threadclass == threadclass) {
409 foundthread = thread;
410 break;
411 }
412 thread = thread->next;
413 } while (thread != finishedthreadlist);
414 }
415 thread = threadlist;
416 if (!foundthread && thread) {
417 do {
418 if (thread->threadclass == threadclass) {
419 foundthread = thread;
420 break;
421 }
422 thread = thread->next;
423 } while (thread != threadlist);
424 }
425 pthread_mutex_unlock(&threadlock);
426 if (foundthread) {
427 return 1;
428 } else {
429 return 0;
430 }
431 }
432
433 void
janitor_thread_joinall(janitor_threadclass_t threadclass)434 janitor_thread_joinall(janitor_threadclass_t threadclass)
435 {
436 int moreleft;
437 do {
438 moreleft = janitor_thread_tryjoinall(threadclass);
439 } while(moreleft);
440 }
441
442 static void
dumpthreads(void)443 dumpthreads(void)
444 {
445 struct janitor_thread_struct* info;
446 struct janitor_thread_struct* list;
447 pthread_mutex_lock(&threadlock);
448 info = pthread_getspecific(threadlocator);
449 list = threadlist;
450 if (list) {
451 do {
452 if (list != info) {
453 pthread_kill(list->thread, SIGQUIT);
454 pthread_cond_wait(&threadblock, &threadlock);
455 }
456 list = list->next;
457 } while (list != threadlist);
458 }
459 pthread_mutex_unlock(&threadlock);
460 }
461
462 #ifdef HAVE_BACKTRACE_FULL
463 static struct backtrace_state *state = NULL;
464 static struct backtrace_state *frames = NULL;
465 static pthread_mutex_t frameslock = PTHREAD_MUTEX_INITIALIZER;
466
467 static int
callback(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)468 callback(void* data, uintptr_t pc, const char *filename, int lineno, const char *function)
469 {
470 if (filename == NULL && lineno == 0 && function == NULL) {
471 alert(" inlined method\n");
472 } else {
473 alert(" %s:%d in %s()\n", filename, lineno, function);
474 }
475 if (function && !strcmp(function, "main"))
476 return 1;
477 else
478 return 0;
479 }
480
481 static void
errorhandler(void * data,const char * msg,int xerrno)482 errorhandler(void* data, const char *msg, int xerrno)
483 {
484 int len = strlen(msg);
485 (void) (write(2, msg, len));
486 (void) (write(2, "\n", 1));
487 }
488 #endif
489
490 static void
outputbacktrace(int skips,void * workaround)491 outputbacktrace(int skips, void *workaround)
492 {
493 #ifdef HAVE_BACKTRACE_FULL
494 struct backtrace_state *state = (struct backtrace_state*) workaround;
495 #else
496 #ifdef HAVE_BACKTRACE
497 Dl_info btinfo;
498 void *bt[20];
499 int count, i;
500 #else
501 #ifdef HAVE_LIBUNWIND
502 unw_context_t ctx;
503 unw_cursor_t cursor;
504 char symbol[256];
505 unw_word_t offset;
506 #endif
507 #endif
508 #endif
509 #ifdef HAVE_BACKTRACE_FULL
510 backtrace_full(state, skips, (backtrace_full_callback) callback, (backtrace_error_callback) errorhandler, NULL);
511 #else
512 #ifdef HAVE_BACKTRACE
513 count = backtrace(bt, sizeof (bt) / sizeof (void*));
514 for (i = skips; i < count; i++) {
515 dladdr(bt[i], &btinfo);
516 if (btinfo.dli_sname != NULL) {
517 alert(" %s\n", btinfo.dli_sname);
518 if (!strcmp(btinfo.dli_sname, "main"))
519 break;
520 } else
521 alert(" unknown\n");
522 }
523 #else
524 #ifdef HAVE_LIBUNWIND
525 unw_getcontext(&ctx);
526 unw_init_local(&cursor, &ctx);
527 if (unw_step(&cursor)) {
528 /* skip the first one */
529 while (unw_step(&cursor)) {
530 unw_get_proc_name(&cursor, symbol, sizeof (symbol) - (skips-1), &offset);
531 alert(" %s\n", symbol);
532 if (!strcmp(symbol, "main"))
533 break;
534 }
535 }
536 #endif
537 #endif
538 #endif
539 }
540
541 static void
handlesignal(int signal,siginfo_t * info,void * data)542 handlesignal(int signal, siginfo_t* info, void* data)
543 {
544 const char* signalname;
545 Dl_info btinfo;
546 janitor_thread_t thrinfo;
547 (void) signal;
548 (void) data;
549 #ifndef HAVE_BACKTRACE_FULL
550 #ifdef HAVE_BACKTRACE
551 void *bt[20];
552 int count, i;
553 #else
554 #ifdef HAVE_LIBUNWIND
555 unw_context_t ctx;
556 unw_cursor_t cursor;
557 char symbol[256];
558 unw_word_t offset;
559 #endif
560 #endif
561 #endif
562 switch (info->si_signo) {
563 case SIGQUIT:
564 signalname = "Threaddump";
565 break;
566 case SIGABRT:
567 sigaction(info->si_signo, &original_abrt_action, NULL);
568 signalname = "Aborted";
569 break;
570 case SIGSEGV:
571 sigaction(info->si_signo, &original_segv_action, NULL);
572 signalname = "Segmentation fault";
573 break;
574 case SIGFPE:
575 sigaction(info->si_signo, &original_fpe_action, NULL);
576 signalname = "Floating point error";
577 break;
578 case SIGILL:
579 sigaction(info->si_signo, &original_ill_action, NULL);
580 signalname = "Illegal instruction";
581 break;
582 case SIGBUS:
583 sigaction(info->si_signo, &original_bus_action, NULL);
584 signalname = "Bus error";
585 break;
586 case SIGSYS:
587 sigaction(info->si_signo, &original_sys_action, NULL);
588 signalname = "System error";
589 break;
590 default:
591 signalname = "Unknown error";
592 }
593 if (dladdr(info->si_addr, &btinfo) != 0)
594 alert("%s in %s", signalname, btinfo.dli_sname);
595 else
596 alert("%s", signalname);
597 #ifdef HAVE_BACKTRACE_FULL
598 alert(":\n");
599 #else
600 #ifdef HAVE_BACKTRACE
601 alert(":\n");
602 #else
603 #ifdef HAVE_LIBUNWIND
604 alert(":\n");
605 #else
606 alert("\n");
607 #endif
608 #endif
609 #endif
610 #ifdef HAVE_BACKTRACE_FULL
611 outputbacktrace(2, state);
612 #else
613 outputbacktrace(2, NULL);
614 #endif
615 if (info->si_signo == SIGQUIT) {
616 pthread_mutex_lock(&threadlock);
617 pthread_cond_signal(&threadblock);
618 pthread_mutex_unlock(&threadlock);
619 } else {
620 dumpthreads();
621 raise(info->si_signo);
622 }
623 }
624
625 void
janitor_backtrace(void)626 janitor_backtrace(void)
627 {
628 #ifdef HAVE_BACKTRACE_FULL
629 if(frames == NULL) {
630 frames = backtrace_create_state(NULL, 0, (backtrace_error_callback) errorhandler, NULL);
631 }
632 pthread_mutex_lock(&frameslock);
633 outputbacktrace(1, frames);
634 pthread_mutex_unlock(&frameslock);
635 #else
636 outputbacktrace(1, NULL);
637 #endif
638 }
639
640 static int
callbackstring(void * data,uintptr_t pc,const char * filename,int lineno,const char * function)641 callbackstring(void* data, uintptr_t pc, const char *filename, int lineno, const char *function)
642 {
643 int siz, len;
644 char** ptr = data;
645 if (filename != NULL || lineno != 0 || function == NULL) {
646 siz = snprintf(NULL, 0, " %s:%d in %s()\n", filename, lineno, function);
647 if (*ptr != NULL) {
648 len = strlen(*ptr);
649 siz += len + 1;
650 *ptr = realloc(*ptr, siz);
651 } else {
652 len = 0;
653 siz += 1;
654 *ptr = malloc(siz);
655 }
656 snprintf(&(*ptr)[len], siz-len, " %s:%d in %s()\n", filename, lineno, function);
657 }
658 if (function && !strcmp(function, "main"))
659 return 1;
660 else
661 return 0;
662 }
663
664 char*
janitor_backtrace_string(void)665 janitor_backtrace_string(void)
666 {
667 char* string = NULL;
668 #ifdef HAVE_BACKTRACE_FULL
669 if(frames == NULL) {
670 frames = backtrace_create_state(NULL, 0, (backtrace_error_callback) errorhandler, NULL);
671 }
672 pthread_mutex_lock(&frameslock);
673 backtrace_full(frames, 1, (backtrace_full_callback) callbackstring, (backtrace_error_callback) errorhandler, &string);
674 pthread_mutex_unlock(&frameslock);
675 #endif
676 return string;
677 }
678
679 void
janitor_backtrace_all(void)680 janitor_backtrace_all(void)
681 {
682 dumpthreads();
683 }
684
685 int
janitor_trapsignals(char * argv0)686 janitor_trapsignals(char* argv0)
687 {
688 sigset_t mask;
689 stack_t ss;
690 struct sigaction newsigaction;
691 static struct backtrace_state *frames;
692
693 #ifdef HAVE_BACKTRACE_FULL
694 CHECKFAIL((state = backtrace_create_state(argv0, 0, (backtrace_error_callback)errorhandler, NULL)) == NULL);
695 CHECKFAIL((frames = backtrace_create_state(argv0, 0, (backtrace_error_callback)errorhandler, NULL)) == NULL);
696 #else
697 (void) argv0;
698 #endif
699
700 /*ss.ss_sp = malloc(SIGSTKSZ);
701 ss.ss_size = SIGSTKSZ;
702 ss.ss_flags = 0;
703 CHECKFAIL(sigaltstack(&ss, NULL) == -1);*/
704
705 sigfillset(&mask);
706 sigdelset(&mask, SIGQUIT);
707 newsigaction.sa_sigaction = handlesignal;
708 newsigaction.sa_flags = SA_SIGINFO | SA_ONSTACK;
709 newsigaction.sa_mask = mask;
710 CHECKFAIL(sigaction(SIGQUIT, &newsigaction, &original_quit_action));
711 CHECKFAIL(sigaction(SIGABRT, &newsigaction, &original_abrt_action));
712 CHECKFAIL(sigaction(SIGSEGV, &newsigaction, &original_segv_action));
713 CHECKFAIL(sigaction(SIGFPE, &newsigaction, &original_fpe_action));
714 CHECKFAIL(sigaction(SIGILL, &newsigaction, &original_ill_action));
715 CHECKFAIL(sigaction(SIGBUS, &newsigaction, &original_bus_action));
716 CHECKFAIL(sigaction(SIGSYS, &newsigaction, &original_sys_action));
717 return 0;
718 fail:
719 return -1;
720 }
721
722 int
janitor_disablecoredump(void)723 janitor_disablecoredump(void)
724 {
725 struct rlimit rlim;
726 rlim.rlim_cur = 0;
727 rlim.rlim_max = 0;
728
729 CHECKFAIL(setrlimit(RLIMIT_CORE, &rlim));
730 return 0;
731 fail:
732 return -1;
733 }
734
735 struct janitor_pthread_barrier_struct {
736 pthread_mutex_t mutex;
737 pthread_cond_t cond;
738 unsigned int waiting;
739 unsigned int count;
740 };
741
742 int
janitor_pthread_barrier_init(pthread_barrier_t * barrier,const pthread_barrierattr_t * attr,unsigned int count)743 janitor_pthread_barrier_init(pthread_barrier_t* barrier, const pthread_barrierattr_t* attr, unsigned int count)
744 {
745 struct janitor_pthread_barrier_struct* b;
746 b = malloc(sizeof(struct janitor_pthread_barrier_struct));
747 if(count == 0 || attr != NULL) {
748 errno = EINVAL;
749 return -1;
750 }
751 if(pthread_mutex_init(&b->mutex, 0) < 0) {
752 free(b);
753 return -1;
754 }
755 if(pthread_cond_init(&b->cond, 0) < 0) {
756 pthread_mutex_destroy(&b->mutex);
757 free(b);
758 return -1;
759 }
760 b->count = count;
761 b->waiting = 0;
762 *(void**)barrier = b;
763 return 0;
764 }
765
766 int
janitor_pthread_barrier_destroy(pthread_barrier_t * barrier)767 janitor_pthread_barrier_destroy(pthread_barrier_t* barrier)
768 {
769 struct janitor_pthread_barrier_struct* b = *(void**)barrier;
770 pthread_mutex_lock(&b->mutex);
771 if(b->count > 0) {
772 pthread_mutex_unlock(&b->mutex);
773 errno = EBUSY;
774 return -1;
775 }
776 *(void**)barrier = NULL;
777 pthread_mutex_unlock(&b->mutex);
778 pthread_cond_destroy(&b->cond);
779 pthread_mutex_destroy(&b->mutex);
780 free(b);
781 return 0;
782 }
783
784 int
janitor_pthread_barrier_wait(pthread_barrier_t * barrier)785 janitor_pthread_barrier_wait(pthread_barrier_t* barrier)
786 {
787 struct janitor_pthread_barrier_struct* b = *(void**)barrier;
788 pthread_mutex_lock(&b->mutex);
789 b->waiting += 1;
790 if(b->waiting == b->count) {
791 b->count = 0;
792 pthread_cond_broadcast(&b->cond);
793 pthread_mutex_unlock(&b->mutex);
794 return PTHREAD_BARRIER_SERIAL_THREAD;
795 } else {
796 pthread_cond_wait(&b->cond, &b->mutex);
797 pthread_mutex_unlock(&b->mutex);
798 return 0;
799 }
800 }
801