在UNIX系統中,守護進程遵循下列公共慣例:
實例
程序清單13-3所示程序說明了守護進程可以重讀其配置文件的一種方法。該程序使用sigwait以及多線程(可參考http://www.CUOXin.com/nufangrensheng/p/3540453.html)。
程序清單13-3 守護進程重讀配置文件
#include "apue.h"#include <pthread.h>#include <syslog.h>sigset_t mask;extern int already_running(void);void reread(void){ /* ... */}void *thr_fn(void *arg){ int err, signo; for(;;) { err = sigwait(&mask, &signo); if(err != 0) { syslog(LOG_ERR, "sigwait failed"); exit(1); } switch(signo) { case SIGHUP: syslog(LOG_INFO, "Re-reading configuration file"); reread(); break; case SIGTERM: syslog(LOG_INFO, "got SIGTERM; exiting"); exit(0); default: syslog(LOG_INFO, "unexpected signal %d/n", signo); } } return(0);}intmain(int argc, char *argv[]){ int err; pthread_t tid; char *cmd; struct sigaction sa; if((cmd = strrchr(argv[0], '/')) == NULL) cmd = argv[0]; else cmd++; /* * Become a daemon. */ daemonize(cmd); /* * Make sure only one copy of the daemon is running. */ if(already_running()) { syslog(LOG_ERR, "daemon already running"); exit(1); } /* * Restore SIGHUP default and block all signals. */ sa.sa_handler = SIG_DFL; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if(sigaction(SIGHUP, &sa, NULL) < 0) err_quit("%s: can't restore SIGHUP default"); sigfillset(&mask); if((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0) err_exit(err, "SIG_BLOCK error"); /* * Create a thread to handle SIGHUP and SIGTERM. */ err = pthread_create(&tid, NULL, thr_fn, 0); if(err != 0) err_exit(err, "can't create thread"); /* * PRoceed with the rest of the daemon. */ /* ... */ exit(0);}
該程序調用http://www.CUOXin.com/nufangrensheng/p/3544104.html中的daemonize以初始化守護進程。從該函數返回后,調用http://www.CUOXin.com/nufangrensheng/p/3544370.html中的already_running函數以確保該守護進程只有一個副本在運行。到達這一點時,SIGHUP信號仍被忽略(???),所以需要恢復對該信號的系統默認處理方式;否則調用sigwait的線程決不會見到該信號。
如同對多線程程序所推薦的那樣,我們阻塞所以信號,然后創建一線程,由它來處理信號。該線程的唯一工作是等待SIGHUP和SIGTERM。當接收到SIGHUP信號時,該線程調用reread函數重讀它的配置文件。當它接收到SIGTERM信號時,記錄一消息,然后終止。
回憶http://www.CUOXin.com/nufangrensheng/p/3514157.html中的表10-1,對于SIGHUP和SIGTERM的默認動作是終止進程。因為我們阻塞了這些信號,所以當對進程產生這些信號時,守護進程不會消亡,而是調用sigwait的線程在返回時將指示已接收到該信號。
實例
如在http://www.CUOXin.com/nufangrensheng/p/3540453.html中所說的那樣,linux線程對于信號的處理方式與眾不同。由于這一點,在程序清單13-3中對信號標識合適的進程是困難的。另外,由于實現的差別,不能保證守護進程將按所期望的那樣作出反應。
程序清單13-4說明守護進程無需使用多線程也可以捕捉SIGHUP并重讀其配置文件。
#include "apue.h"#include <syslog.h>#include <errno.h>extern int lockfile(int);extern int already_running(void);void reread(void){ /* ... */}void sigterm(int signo){ syslog(LOG_INFO, "got SIGTERM; exiting"); exit(0);}voidsighup(int signo){ syslog(LOG_INFO, "Re-reading configuration file"); reread();}intmain(int argc, char *argv[]){ char *cmd; struct sigaction sa; if((cmd = strrchr(argv[0], '/')) == NULL) cmd = argv[0]; else cmd++; /* * Become a daemon. */ daemonize(cmd); /* * Make sure only one copy of the daemon is running. */ if(already_running()) { syslog(LOG_ERR, "daemon already running"); exit(1); } /* * Handle signals of interest. */ sa.sa_handler = sigterm; sigempty(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGHUP); sa.sa_flags = 0; if(sigaction(SIGTERM, &sa, NULL) < 0) { syslog(LOG_ERR, "can't catch SIGTERM: %s", strerror(errno)); exit(1); } sa.sa_handler = sighup; sigemptyset(&sa.sa_mask); sigaddset(&sa.sa_mask, SIGTERM); sa.sa_flags = 0; if(sigaction(SIGHUP, &sa, NULL) < 0) { syslog(LOG_ERR, "can't catch SIGHUP: %s", strerror(errno)); exit(1); } /* * Proceed with the rest of the daemon. */ /* ... */ exit(0); }
在初始化守護進程后,我們為SIGHUP和SIGTERM配置信號處理程序。我們可以將重讀邏輯放在信號處理程序中,也可以只在其中設置一個標志,由守護進程的主線程做所有所需的工作。
本篇博文內容摘自《UNIX環境高級編程》(第二版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/。
新聞熱點
疑難解答