unix 的信號signal經常使用於進程管理.
好比管理員或者操做系統經過向master進程實現重啓和關閉服務.
master進程經過向worker進程發信號管理worker進程.php
一般會在進程自定義信號處理函數,處理相關的邏輯.
自定義信號處理函數,從使用者的角度看,很簡單,有點像快捷鍵的定製.數組
//fpm_signals.c #include "fpm_config.h" ... //整數數組,存放socketpair建立的管道兩端文件句柄 static int sp[2]; ... //worker進程信號處理函數 static void sig_soft_quit(int signo) /* {{{ */ { int saved_errno = errno; /* closing fastcgi listening socket will force fcgi_accept() exit immediately */ close(0); if (0 > socket(AF_UNIX, SOCK_STREAM, 0)) { zlog(ZLOG_WARNING, "failed to create a new socket"); } fpm_php_soft_quit(); errno = saved_errno; } //master進程信號處理函數 static void sig_handler(int signo) /* {{{ */ { //C99 的數組初始化語法 //信號整數和字符的對應關係. static const char sig_chars[NSIG + 1] = { [SIGTERM] = 'T', [SIGINT] = 'I', [SIGUSR1] = '1', [SIGUSR2] = '2', [SIGQUIT] = 'Q', [SIGCHLD] = 'C' }; char s; int saved_errno; if (fpm_globals.parent_pid != getpid()) { return; } saved_errno = errno; s = sig_chars[signo]; //信號對應的字符寫到管道 write(sp[1], &s, sizeof(s)); errno = saved_errno; } int fpm_signals_init_main() /* {{{ */ { struct sigaction act; //建立socketpair管道,管道兩端的文件句柄fd 放在數組sp裏 if (0 > socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) { zlog(ZLOG_SYSERROR, "failed to init signals: socketpair()"); return -1; } if (0 > fd_set_blocked(sp[0], 0) || 0 > fd_set_blocked(sp[1], 0)) { zlog(ZLOG_SYSERROR, "failed to init signals: fd_set_blocked()"); return -1; } if (0 > fcntl(sp[0], F_SETFD, FD_CLOEXEC) || 0 > fcntl(sp[1], F_SETFD, FD_CLOEXEC)) { zlog(ZLOG_SYSERROR, "falied to init signals: fcntl(F_SETFD, FD_CLOEXEC)"); return -1; } memset(&act, 0, sizeof(act)); act.sa_handler = sig_handler; //全部信號使用同一個處理函數 sigfillset(&act.sa_mask); if (0 > sigaction(SIGTERM, &act, 0) || 0 > sigaction(SIGINT, &act, 0) || 0 > sigaction(SIGUSR1, &act, 0) || 0 > sigaction(SIGUSR2, &act, 0) || 0 > sigaction(SIGCHLD, &act, 0) || 0 > sigaction(SIGQUIT, &act, 0)) { zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()"); return -1; } return 0; } int fpm_signals_init_child() { struct sigaction act, act_dfl; memset(&act, 0, sizeof(act)); memset(&act_dfl, 0, sizeof(act_dfl)); act.sa_handler = &sig_soft_quit; act.sa_flags |= SA_RESTART; act_dfl.sa_handler = SIG_DFL; //系統默認動做 //worker 進程不使用socketpair建立的管道 close(sp[0]); close(sp[1]); if (0 > sigaction(SIGTERM, &act_dfl, 0) || 0 > sigaction(SIGINT, &act_dfl, 0) || 0 > sigaction(SIGUSR1, &act_dfl, 0) || 0 > sigaction(SIGUSR2, &act_dfl, 0) || 0 > sigaction(SIGCHLD, &act_dfl, 0) || 0 > sigaction(SIGQUIT, &act, 0)) { zlog(ZLOG_SYSERROR, "failed to init child signals: sigaction()"); return -1; } return 0; } int fpm_signals_get_fd() { return sp[0]; }
master 進程的信號被寫到了管道,管道另外一端的處理:socket
//fpm_events.c static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg) { char c; int res, ret; int fd = ev->fd; do { do { res = read(fd, &c, 1); } while (res == -1 && errno == EINTR); if (res <= 0) { if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { zlog(ZLOG_SYSERROR, "unable to read from the signal pipe"); } return; } //依據讀取到的字符作處理 switch (c) { ... case 'Q' : /* SIGQUIT */ zlog(ZLOG_DEBUG, "received SIGQUIT"); zlog(ZLOG_NOTICE, "Finishing ..."); fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET); break; case '1' : /* SIGUSR1 */ zlog(ZLOG_DEBUG, "received SIGUSR1"); if (0 == fpm_stdio_open_error_log(1)) { zlog(ZLOG_NOTICE, "error log file re-opened"); } else { zlog(ZLOG_ERROR, "unable to re-opened error log file"); } ret = fpm_log_open(1); if (ret == 0) { zlog(ZLOG_NOTICE, "access log file re-opened"); } else if (ret == -1) { zlog(ZLOG_ERROR, "unable to re-opened access log file"); } /* else no access log are set */ break; case '2' : /* SIGUSR2 */ zlog(ZLOG_DEBUG, "received SIGUSR2"); zlog(ZLOG_NOTICE, "Reloading in progress ..."); fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET); break; } if (fpm_globals.is_child) { break; } } while (1); return; }