Redis2.2.2原始碼學習——訊號的處理
阿新 • • 發佈:2019-02-06
Redis對訊號的處理如下:
1)忽略的訊號:SIGHUP(終端session關閉)、SIGPIPE(管道錯誤)
2)出錯相關訊號:SIGSEGV SIGBUS SIGFPE SIGILL
處理方式:觸發段錯誤的處理函式中,
1.主要將錯誤資訊寫入日誌
2.將該訊號處理訊號設定為預設,重新在本身傳送該訊號(執行訊號的預設處理)
3)程序結束訊號:SIGTERM(該訊號用於請求中止程序,kill命令預設傳送)
1.server.shutdown_asap = 1; 和程式出錯訊號相比,SIGTERM屬於正常的終止訊號。所以
訊號處理函式沒有執行系統的預設訊號處理函式。而是在serverCron()函式中,呼叫
prepareForShutdown()函式處理伺服器推出前的後續工作,最後退出。
4)其他訊號: 執行預設處理
p.s. http://blog.chinaunix.net/uid-24599332-id-2122898.html
1) SIGBUS(Bus error)意味著指標所對應的地址是有效地址,但匯流排不能正常使用該指標。通常是未對齊的資料訪問所致。
2) SIGSEGV(Segment fault)意味著指標所對應的地址是無效地址,沒有實體記憶體對應該地址。
3) SIGFPE(floating-point exception)算術錯誤
1)忽略的訊號:SIGHUP(終端session關閉)、SIGPIPE(管道錯誤)
2)出錯相關訊號:SIGSEGV SIGBUS SIGFPE SIGILL
處理方式:觸發段錯誤的處理函式中,
1.主要將錯誤資訊寫入日誌
2.將該訊號處理訊號設定為預設,重新在本身傳送該訊號(執行訊號的預設處理)
3)程序結束訊號:SIGTERM(該訊號用於請求中止程序,kill命令預設傳送)
1.server.shutdown_asap = 1; 和程式出錯訊號相比,SIGTERM屬於正常的終止訊號。所以
訊號處理函式沒有執行系統的預設訊號處理函式。而是在serverCron()函式中,呼叫
prepareForShutdown()函式處理伺服器推出前的後續工作,最後退出。
4)其他訊號: 執行預設處理
p.s. http://blog.chinaunix.net/uid-24599332-id-2122898.html
1) SIGBUS(Bus error)意味著指標所對應的地址是有效地址,但匯流排不能正常使用該指標。通常是未對齊的資料訪問所致。
2) SIGSEGV(Segment fault)意味著指標所對應的地址是無效地址,沒有實體記憶體對應該地址。
3) SIGFPE(floating-point exception)算術錯誤
4) SIGILL(illegal instruction)執行非法指令
--------------------------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[i]); /* 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"); } ... }