dhcp源码中也包含了信号的处理,现在单独拿出来看看代码的逻辑架构,分析下怎么样写一个合理的信号处理。、
先看signal.c里面的实现,如下:
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#include "signals.h"
static int signal_pipe[2]; //定义pipe通信
static const int handle_sigs[] = { //信号数组的定义
SIGALRM,
SIGHUP,
SIGINT,
SIGPIPE,
SIGTERM,
SIGUSR1,
};
//将信号写入管道
static void
signal_handler(int sig)
{
int serrno = errno;
if (write(signal_pipe[1], &sig, sizeof(sig)) != sizeof(sig))
syslog(LOG_ERR, "failed to write signal %d: %m", sig);
/* Restore errno */
errno = serrno;
}
//从管道读入信号
/* Read a signal from the signal pipe. Returns 0 if there is
* no signal, -1 on error (and sets errno appropriately), and
* your signal on success */
int
signal_read(void)
{
int sig = -1;
char buf[16];
ssize_t bytes;
memset(buf, 0, sizeof(buf));
bytes = read(signal_pipe[0], buf, sizeof(buf));
if (bytes >= 0 && (size_t)bytes >= sizeof(sig))
memcpy(&sig, buf, sizeof(sig));
return sig;
}
/* Call this before doing anything else. Sets up the socket pair
* and installs the signal handler */
int
signal_init(void)
{
//定义pipe进程间通信方式,并设置为不阻塞以及防止任何脚本继承pipe
if (pipe(signal_pipe) == -1)
return -1;
/* Don't block on read */
if (set_nonblock(signal_pipe[0]) == -1)
return -1;
/* Stop any scripts from inheriting us */
if (set_cloexec(signal_pipe[0]) == -1)
return -1;
if (set_cloexec(signal_pipe[1]) == -1)
return -1;
// 返回读pipe
return signal_pipe[0];
}
static int
signal_handle(void (*func)(int))
{
unsigned int i;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = func;
sigemptyset(&sa.sa_mask);
//遍历上面信号数组,一旦由上述的信号产生,就会进入到上面的signal_handler里面,注意这里没有屏蔽信号,会中断信号的过程
for (i = 0; i < sizeof(handle_sigs) / sizeof(handle_sigs[0]); i++)
if (sigaction(handle_sigs[i], &sa, NULL) == -1)return -1;return 0;}intsignal_setup(void){
如下:在main函数里面,如下,
if ((signal_fd = signal_init()) == -1)
exit(EXIT_FAILURE);
if (signal_setup() == -1)
exit(EXIT_FAILURE);
add_event(signal_fd, handle_signal, NULL);
* ARGSUSED */
static void
handle_signal(_unused void *arg)
{
struct interface *ifp, *ifl;
struct if_options *ifo;
int sig = signal_read();
int do_release, do_rebind, i;
do_rebind = do_release = 0;
switch (sig) {
case SIGINT:
syslog(LOG_INFO, "received SIGINT, stopping");
break;
case SIGTERM:
syslog(LOG_INFO, "received SIGTERM, stopping");
break;
case SIGALRM:
#ifdef ANDROID
syslog(LOG_INFO, "received SIGALRM, renewing");
for (ifp = ifaces; ifp; ifp = ifp->next) {
start_renew(ifp);
}
#else
syslog(LOG_INFO, "received SIGALRM, rebinding");
for (i = 0; i < ifac; i++)
free(ifav[i]);
free(ifav);
ifav = NULL;
ifac = 0;
for (i = 0; i < ifdc; i++)
free(ifdv[i]);
free(ifdv);
ifdc = 0;
ifdv = NULL;
ifo = read_config(cffile, NULL, NULL, NULL);
add_options(ifo, margc, margv);
/* We need to preserve these two options. */
if (options & DHCPCD_MASTER)
ifo->options |= DHCPCD_MASTER;
if (options & DHCPCD_DAEMONISED)
ifo->options |= DHCPCD_DAEMONISED;
options = ifo->options;
free_options(ifo);
reconf_reboot(1, ifc, ifv, 0);
#endif
return;
case SIGHUP:
syslog(LOG_INFO, "received SIGHUP, releasing");
do_release = 1;
break;
case SIGUSR1:
syslog(LOG_INFO, "received SIGUSR, reconfiguring");
for (ifp = ifaces; ifp; ifp = ifp->next)
if (ifp->state->new)
configure(ifp);
return;
case SIGPIPE:
syslog(LOG_WARNING, "received SIGPIPE");
return;
default:
syslog(LOG_ERR,
"received signal %d, but don't know what to do with it",
sig);
return;
}
//后面与handler无关的先不用管
}
代码实现是:对fd进行相应的poll检测,如果由fd数据到达,就会进入到相应的回调函数里面
因此,当sig来的时候,步骤如下:
1)当sig发生的时候,进入到捕获函数里面,也就是:signal_handler
然后往里面写sig号,即:write(signal_pipe[1], &sig, sizeof(sig)) != sizeof(sig)
2)由于此时event机制死循环,检测到fd发生了变化,于是去读取相应的sig
然后调到了handle_signal
3)最后,通过signal_read 去读取相应的值,这样就实现了整套signal机制。
不过这里有个地方,和平时使用pipe不一样,没有fork进程,直接同一个进程通信,
恩,下次下一个demo看下!
源码第二个使用signal的地方是:configure.c里面,真正执行脚本的时候,
见下面:
static int
exec_script(char *const *argv, char *const *env)
{
pid_t pid;
sigset_t full;
sigset_t old;
/* OK, we need to block signals */
sigfillset(&full);
sigprocmask(SIG_SETMASK, &full, &old);
signal_reset();//使用默认的操作
switch (pid = vfork()) {
case -1:
syslog(LOG_ERR, "vfork: %m");
break;
case 0:
//复原了信号,然后执行脚本
sigprocmask(SIG_SETMASK, &old, NULL);
execve(argv[0], argv, env);
syslog(LOG_ERR, "%s: %m", argv[0]);
_exit(127);
/* NOTREACHED */
}
/* Restore our signals */
signal_setup();//开始信号捕捉函数
sigprocmask(SIG_SETMASK, &old, NULL);
return pid;
}