--------------------------initServer------------------------------------------
void initServer() {
...
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
setupSigSegvAction();
...
}
void setupSigSegvAction(void) {
struct sigaction act;
sigemptyset (&act.sa_mask);
/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
* is used. Otherwise, sa_handler is used */
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
act.sa_sigaction = segvHandler;
sigaction (SIGSEGV, &act, NULL);//段
sigaction (SIGBUS, &act, NULL);//总线
sigaction (SIGFPE, &act, NULL);//算术
sigaction (SIGILL, &act, NULL);//指令
sigaction (SIGBUS, &act, NULL);//两个BUS ?
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
act.sa_handler = sigtermHandler;
sigaction (SIGTERM, &act, NULL);//请求服务器终止
return;
}
----------------------程序出错相关信号的hander---------------------------------
/*1.写服务器出错日志
2.再次执行信号的默认操作(为了core dump?)。
作者的解释:Make sure we exit with the right signal at the end. So for instance
the core will be dumped if enabled.
比如:(http://zh.wikipedia.org/wiki/SIGSEGV)
在一个程序接收到SIGSEGV时的默认动作是异常终止。这个动作也许会结束进程,
但是可能生成一个核心文件(core file)以帮助调试,或者执行一些其他特定于某些平台的动作。例如,
使用了grsecurity补丁的Linux系统可能记录SIGSEGV信号以监视可能的使用缓存溢出的攻击尝试。*/
void segvHandler(int sig, siginfo_t *info, void *secret) {
void *trace[100];
char **messages = NULL;
int i, trace_size = 0;
ucontext_t *uc = (ucontext_t*) secret;
sds infostring;
struct sigaction act;
REDIS_NOTUSED(info);
redisLog(REDIS_WARNING,
"======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
infostring = genRedisInfoString();
redisLog(REDIS_WARNING, "%s",infostring);
/* It's not safe to sdsfree() the returned string under memory
* corruption conditions. Let it leak as we are going to abort */
trace_size = backtrace(trace, 100);
/* overwrite sigaction with caller's address */
if (getMcontextEip(uc) != NULL) {
trace[1] = getMcontextEip(uc);
}
messages = backtrace_symbols(trace, trace_size);
for (i=1; i<trace_size; ++i)
redisLog(REDIS_WARNING,"%s", messages);
/* free(messages); Don't call free() with possibly corrupted memory. */
if (server.daemonize) unlink(server.pidfile);
/* Make sure we exit with the right signal at the end. So for instance
* the core will be dumped if enabled. */
//由于前面篡改了信号处理函数,为何程序按照正常的处理方式退出,这里采用
//将信号处理函数修改为默认,再次向本进程发送该信号,从而执行信号的默认操作(core dump)
sigemptyset (&act.sa_mask);
/* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction
* is used. Otherwise, sa_handler is used */
act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
act.sa_handler = SIG_DFL;
sigaction (sig, &act, NULL);
kill(getpid(),sig);
}
-----------------------SIGTERM信号的hander-----------------------------------------------
//shutdown_asap作为服务器是否进入退出状态的标志
//作者并未在该hander中直接调用服务器退出函数,而仅仅是设置了退出标志。真正的退出在serverCron中调用
//作者这样安排估计是为了程序的规范吧?不知道还有没有其他意义...
void sigtermHandler(int sig) {
REDIS_NOTUSED(sig);
redisLog(REDIS_WARNING,"SIGTERM received, scheduling shutting down...");
server.shutdown_asap = 1;
}
-----------------------serverCron---------------------------------------------------------------
//serverCron作为定时器事件(服务器的协调员,啥事都管)
//在下一次执行是检测到server.shutdown_asap==1,那么执行退出操作
int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
...
/* We received a SIGTERM, shutting down here in a safe way, as it is
* not ok doing so inside the signal handler. */
if (server.shutdown_asap) {
if (prepareForShutdown() == REDIS_OK) exit(0);
redisLog(REDIS_WARNING,"SIGTERM received but errors trying to shut down the server, check the logs for more information");
}
...
}