X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/e4669c045d5bc0f7420814cb66f13f03ac29e29a..6aa2f98938955788c3f56e1ce8fef691233bca35:/src/debug.c diff --git a/src/debug.c b/src/debug.c index 9c8b6ef9..e7b3ba40 100644 --- a/src/debug.c +++ b/src/debug.c @@ -559,10 +559,11 @@ void logRegisters(ucontext_t *uc) { } /* Logs the stack trace using the backtrace() call. */ -void logStackTrace(ucontext_t *uc) { +sds getStackTrace(ucontext_t *uc) { void *trace[100]; int i, trace_size = 0; char **messages = NULL; + sds st = sdsempty(); /* Generate the stack trace */ trace_size = backtrace(trace, 100); @@ -572,9 +573,12 @@ void logStackTrace(ucontext_t *uc) { trace[1] = getMcontextEip(uc); } messages = backtrace_symbols(trace, trace_size); - redisLog(REDIS_WARNING, "--- STACK TRACE"); - for (i=1; i + +void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) { + ucontext_t *uc = (ucontext_t*) secret; + REDIS_NOTUSED(info); + REDIS_NOTUSED(sig); + sds st, log; + + log = sdsnew("\n--- WATCHDOG TIMER EXPIRED ---\n"); +#ifdef HAVE_BACKTRACE + st = getStackTrace(uc); +#else + st = sdsnew("Sorry: no support for backtrace().\n"); +#endif + log = sdscatsds(log,st); + log = sdscat(log,"------\n"); + redisLogFromHandler(REDIS_WARNING,log); + sdsfree(st); + sdsfree(log); +} + +/* Schedule a SIGALRM delivery after the specified period in milliseconds. + * If a timer is already scheduled, this function will re-schedule it to the + * specified time. If period is 0 the current timer is disabled. */ +void watchdogScheduleSignal(int period) { + struct itimerval it; + + /* Will stop the timer if period is 0. */ + it.it_value.tv_sec = period/1000; + it.it_value.tv_usec = (period%1000)*1000; + /* Don't automatically restart. */ + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + setitimer(ITIMER_REAL, &it, NULL); +} + +/* Enable the software watchdong with the specified period in milliseconds. */ +void enableWatchdog(int period) { + if (server.watchdog_period == 0) { + struct sigaction act; + + /* Watchdog was actually disabled, so we have to setup the signal + * handler. */ + sigemptyset(&act.sa_mask); + act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_SIGINFO; + act.sa_sigaction = watchdogSignalHandler; + sigaction(SIGALRM, &act, NULL); + } + if (period < 200) period = 200; /* We don't accept periods < 200 ms. */ + watchdogScheduleSignal(period); /* Adjust the current timer. */ + server.watchdog_period = period; +} + +/* Disable the software watchdog. */ +void disableWatchdog(void) { + struct sigaction act; + if (server.watchdog_period == 0) return; /* Already disabled. */ + watchdogScheduleSignal(0); /* Stop the current timer. */ + + /* Set the signal handler to SIG_IGN, this will also remove pending + * signals from the queue. */ + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = SIG_IGN; + sigaction(SIGALRM, &act, NULL); + server.watchdog_period = 0; +}