#ifdef HAVE_BACKTRACE
#include <execinfo.h>
#include <ucontext.h>
+#include <fcntl.h>
#endif /* HAVE_BACKTRACE */
/* ================================= Debugging ============================== */
#endif
}
-/* Logs the stack trace using the backtrace() call. */
-sds getStackTrace(ucontext_t *uc) {
+/* Logs the stack trace using the backtrace() call. This function is designed
+ * to be called from signal handlers safely. */
+void logStackTrace(ucontext_t *uc) {
void *trace[100];
- int i, trace_size = 0;
- char **messages = NULL;
- sds st = sdsempty();
+ int trace_size = 0, fd;
+
+ /* Open the log file in append mode. */
+ fd = server.logfile ?
+ open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644) :
+ STDOUT_FILENO;
+ if (fd == -1) return;
/* Generate the stack trace */
trace_size = backtrace(trace, 100);
/* overwrite sigaction with caller's address */
- if (getMcontextEip(uc) != NULL) {
+ if (getMcontextEip(uc) != NULL)
trace[1] = getMcontextEip(uc);
- }
- messages = backtrace_symbols(trace, trace_size);
- for (i=1; i<trace_size; ++i) {
- st = sdscat(st,messages[i]);
- st = sdscatlen(st,"\n",1);
- }
- zlibc_free(messages);
- return st;
+
+ /* Write symbols to log file */
+ backtrace_symbols_fd(trace, trace_size, fd);
+
+ /* Cleanup */
+ if (server.logfile) close(fd);
}
/* Log information about the "current" client, that is, the client that is
void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
ucontext_t *uc = (ucontext_t*) secret;
- sds infostring, clients, st;
+ sds infostring, clients;
struct sigaction act;
REDIS_NOTUSED(info);
server.assert_file, server.assert_line);
/* Log the stack trace */
- st = getStackTrace(uc);
- redisLog(REDIS_WARNING, "--- STACK TRACE\n%s", st);
- sdsfree(st);
+ redisLog(REDIS_WARNING, "--- STACK TRACE");
+ logStackTrace(uc);
/* Log INFO and CLIENT LIST */
redisLog(REDIS_WARNING, "--- INFO OUTPUT");
}
#endif /* HAVE_BACKTRACE */
+/* ==================== Logging functions for debugging ===================== */
+
+void redisLogHexDump(int level, char *descr, void *value, size_t len) {
+ char buf[65], *b;
+ unsigned char *v = value;
+ char charset[] = "0123456789abcdef";
+
+ redisLog(level,"%s (hexdump):", descr);
+ b = buf;
+ while(len) {
+ b[0] = charset[(*v)>>4];
+ b[1] = charset[(*v)&0xf];
+ b[2] = '\0';
+ b += 2;
+ len--;
+ v++;
+ if (b-buf == 64 || len == 0) {
+ redisLogRaw(level|REDIS_LOG_RAW,buf);
+ b = buf;
+ }
+ }
+ redisLogRaw(level|REDIS_LOG_RAW,"\n");
+}
+
/* =========================== Software Watchdog ============================ */
#include <sys/time.h>
#endif
REDIS_NOTUSED(info);
REDIS_NOTUSED(sig);
- sds st, log;
- log = sdsnew("\n--- WATCHDOG TIMER EXPIRED ---\n");
+ redisLogFromHandler(REDIS_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---");
#ifdef HAVE_BACKTRACE
- st = getStackTrace(uc);
+ logStackTrace(uc);
#else
- st = sdsnew("Sorry: no support for backtrace().\n");
+ redisLogFromHandler(REDIS_WARNING,"Sorry: no support for backtrace().");
#endif
- log = sdscatsds(log,st);
- log = sdscat(log,"------\n");
- redisLogFromHandler(REDIS_WARNING,log);
- sdsfree(st);
- sdsfree(log);
+ redisLogFromHandler(REDIS_WARNING,"--------\n");
}
/* Schedule a SIGALRM delivery after the specified period in milliseconds.
/* Enable the software watchdong with the specified period in milliseconds. */
void enableWatchdog(int period) {
+ int min_period;
+
if (server.watchdog_period == 0) {
struct sigaction act;
act.sa_sigaction = watchdogSignalHandler;
sigaction(SIGALRM, &act, NULL);
}
- if (period < 200) period = 200; /* We don't accept periods < 200 ms. */
+ /* If the configured period is smaller than twice the timer period, it is
+ * too short for the software watchdog to work reliably. Fix it now
+ * if needed. */
+ min_period = (1000/REDIS_HZ)*2;
+ if (period < min_period) period = min_period;
watchdogScheduleSignal(period); /* Adjust the current timer. */
server.watchdog_period = period;
}