X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fsig-monitor.c;h=759825073e2737fe91b4d1cd46ac097ff9be6c62;hb=bee892ba769f78ede968ad9b6aea006b6aee26e9;hp=bd1311a9620c75edb521adc258068562c7a29e01;hpb=859e455780dccf2cbe4f2a94a65e4639e6c7e183;p=src%2Fapp-framework-binder.git diff --git a/src/sig-monitor.c b/src/sig-monitor.c index bd1311a9..75982507 100644 --- a/src/sig-monitor.c +++ b/src/sig-monitor.c @@ -18,6 +18,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -33,6 +34,7 @@ /* local handler */ static _Thread_local sigjmp_buf *error_handler; +static _Thread_local int in_safe_dumpstack; /* local timers */ static _Thread_local int thread_timer_set; @@ -41,23 +43,57 @@ static _Thread_local timer_t thread_timerid; /* * Dumps the current stack */ -static void dumpstack(int crop) +static void dumpstack(int crop, int signum) { - int idx, count; - void *addresses[1000]; + int idx, count, rc; + void *addresses[100]; char **locations; + char buffer[8000]; + size_t pos, length; count = backtrace(addresses, sizeof addresses / sizeof *addresses); - locations = backtrace_symbols(addresses, count); + if (count <= crop) + crop = 0; + count -= crop; + locations = backtrace_symbols(&addresses[crop], count); if (locations == NULL) ERROR("can't get the backtrace (returned %d addresses)", count); else { - for (idx = crop; idx < count; idx++) - ERROR("[BACKTRACE %d/%d] %s", idx - crop + 1, count - crop, locations[idx]); + length = sizeof buffer - 1; + pos = 0; + idx = 0; + while (pos < length && idx < count) { + rc = snprintf(&buffer[pos], length - pos, " [%d/%d] %s\n", idx + 1, count, locations[idx]); + pos += rc >= 0 ? rc : 0; + idx++; + } + buffer[length] = 0; + if (signum) + ERROR("BACKTRACE due to signal %s/%d:\n%s", strsignal(signum), signum, buffer); + else + ERROR("BACKTRACE:\n%s", buffer); free(locations); } } +static void safe_dumpstack_cb(int signum, void *closure) +{ + int *args = closure; + if (signum) + ERROR("Can't provide backtrace: raised signal %s", strsignal(signum)); + else + dumpstack(args[0], args[1]); +} + +static void safe_dumpstack(int crop, int signum) +{ + int args[2] = { crop, signum }; + + in_safe_dumpstack = 1; + sig_monitor(0, safe_dumpstack_cb, args); + in_safe_dumpstack = 0; +} + /* * Creates a timer for the current thread * @@ -129,7 +165,11 @@ static inline void timeout_delete() /* Handles signals that terminate the process */ static void on_signal_terminate (int signum) { - ERROR("Terminating signal %d received: %s", signum, strsignal(signum)); + if (!in_safe_dumpstack) { + ERROR("Terminating signal %d received: %s", signum, strsignal(signum)); + if (signum == SIGABRT) + safe_dumpstack(3, signum); + } exit(1); } @@ -138,19 +178,19 @@ static void on_signal_error(int signum) { sigset_t sigset; + if (in_safe_dumpstack) + longjmp(*error_handler, signum); + ERROR("ALERT! signal %d received: %s", signum, strsignal(signum)); if (error_handler == NULL && signum == SIG_FOR_TIMER) return; - dumpstack(3); + safe_dumpstack(3, signum); // unlock signal to allow a new signal to come - if (error_handler != NULL) { - sigemptyset(&sigset); - sigaddset(&sigset, signum); - sigprocmask(SIG_UNBLOCK, &sigset, 0); + if (error_handler != NULL) longjmp(*error_handler, signum); - } + ERROR("Unmonitored signal %d received: %s", signum, strsignal(signum)); exit(2); } @@ -159,9 +199,14 @@ static void on_signal_error(int signum) static int install(void (*handler)(int), int *signals) { int result = 1; + struct sigaction sa; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_NODEFER; while(*signals > 0) { - if (signal(*signals, handler) == SIG_ERR) { - ERROR("failed to install signal handler for signal %s", strsignal(*signals)); + if (sigaction(*signals, &sa, NULL) < 0) { + ERROR("failed to install signal handler for signal %s: %m", strsignal(*signals)); result = 0; } signals++;