redis在2.6?版本实现了软看门狗,利用setitimer产生SIGALRM信号量实现,并且需要定期喂狗,如果没有喂则回触发一次
样例代码如下,可利用代码实现慢操作跟踪/logStackTrace可用于实现coredump的函数栈打印
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
//backtrace
#include <execinfo.h>
#define HAVE_BACKTRACE 1
typedef struct server{
int watchdog_period;
int hz; /* serverCron() calls frequency in hertz */
char logfile[10];
}server_t;
server_t server = {
.watchdog_period = 0,
.hz = 10,
.logfile[0] = '\0',
};
#ifdef HAVE_BACKTRACE
static void *getMcontextEip(ucontext_t *uc) {
return (void*) uc->uc_mcontext.gregs[16]; /* Linux 64 */
}
#endif
/* Return a file descriptor to write directly to the Redis log with the
* write(2) syscall, that can be used in critical sections of the code
* where the rest of Redis can't be trusted (for example during the memory
* test) or when an API call requires a raw fd.
*
* Close it with closeDirectLogFiledes(). */
int openDirectLogFiledes(void) {
int log_to_stdout = server.logfile[0] == '\0';
int fd = log_to_stdout ?
STDOUT_FILENO :
open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644);
return fd;
}
/* Used to close what closeDirectLogFiledes() returns. */
void closeDirectLogFiledes(int fd) {
int log_to_stdout = server.logfile[0] == '\0';
if (!log_to_stdout) close(fd);
}
/* 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[101];
int trace_size = 0, fd = openDirectLogFiledes();
if (fd == -1) return; /* If we can't log there is anything to do. */
/* Generate the stack trace */
trace_size = backtrace(trace+1, 100);
if (getMcontextEip(uc) != NULL) {
char *msg1 = "EIP:\n";
char *msg2 = "\nBacktrace:\n";
if (write(fd,msg1,strlen(msg1)) == -1) {/* Avoid warning. */};
trace[0] = getMcontextEip(uc);
backtrace_symbols_fd(trace, 1, fd);
if (write(fd,msg2,strlen(msg2)) == -1) {/* Avoid warning. */};
}
/* Write symbols to log file */
backtrace_symbols_fd(trace+1, trace_size, fd);
/* Cleanup */
closeDirectLogFiledes(fd);
}
void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) {
#ifdef HAVE_BACKTRACE
ucontext_t *uc = (ucontext_t*) secret;
#else
(void)secret;
#endif
//serverLogFromHandler(LL_WARNING,"\n--- WATCHDOG TIMER EXPIRED ---");
#ifdef HAVE_BACKTRACE
logStackTrace(uc);
#else
#endif
printf("--------\n");
}
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 watchdog with the specified period in milliseconds. */
void enableWatchdog(int period) {
int min_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_SIGINFO;
act.sa_sigaction = watchdogSignalHandler;
sigaction(SIGALRM, &act, NULL);
}
/* 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/server.hz)*2;
if (period < min_period) period = min_period;
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;
}
int fun2()
{
sleep(1);
return 0;
}
int fun1()
{
fun2();
return 1+2;
}
int main()
{
enableWatchdog(500);
while(1){
usleep(100*1000);
fun1();
//feed dog
if (server.watchdog_period) watchdogScheduleSignal(server.watchdog_period);
}
return 1;
}
//gcc -g -rdynamic watchdog.c -o watchdog