分类:
2008-12-08 11:41:30
10.3 signal function
#include void (*signal(int signo, void (*func)(int)))(int); |
Returns: previous disposition of signal (see following) if OK, SIG_ERR
on error |
1.这个函数用来安装signal的handler。当然有些信号是不能有我们自定义handler的如SIGSTOP和SIGKILL.这个函数声明有点晦涩,可以这样看:
Typedef void (*funcPtr)(int);
funcPtr signal(int signo, funcPtr func);
2.这个函数有个缺点,即,我们没有方法测试当前进程是否针对某个signal设置了handler,而能通过修改当前进程对某个signal的handler函数后才能通过返回值得到旧的handler函数。所以使用sigaction比signal要方便,如下是signal的例子:
void sig_int(int), sig_quit(int);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, sig_int);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, sig_quit);
上述返回值的一些定义:
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1
3.一个刚启动的进程,其各个signal的handler要么忽略,要么都是默认的。一个fork出来的子进程它会继承父亲设置的对一些signal的handler。然而一旦子进程执行了exec调用,这个继承就被冲掉了,因为父进程里handler函数的地址对于新的exec的进程显然没有什么意义了。
4.下面有一个使用SIGUSR1信号的例子:
#include "apue.h"
static void sig_usr(int); /* one handler for both signals */
int
main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
err_sys("can't catch SIGUSR1");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
err_sys("can't catch SIGUSR2");
for ( ; ; )
pause();
}
static void
sig_usr(int signo) /* argument is signal number */
{
if (signo == SIGUSR1)
printf("received SIGUSR1\n");
else if (signo == SIGUSR2)
printf("received SIGUSR2\n");
else
err_dump("received signal %d\n", signo);
}
注意,pause()函数相当于使本执行体wait,仅当收到一个signal时才返回,且返回-1, errno被设置为EINTR,表明pause被打断了。或者本进程直接收到了不能被捕获的结束信号而结束(就不会再返回了)。所以我们可以加上如下代码:
If( pause() == -1 )
Puts(“we received a signal”);
但是,一般的用法是使用pause()来作为一个执行体的结束点,即pause()使其等待信号,并且设置了相应的handler,等信号以来,相应的handler被处理后,pause返回,然后就结束。有个问题,我怎么只知道是收到了那个信号呢?
结果如下:
$ ./a.out & start process in background
[1] 7216 job-control shell prints job number and process ID
$ kill -USR1 7216 send it SIGUSR1
received SIGUSR1
$ kill -USR2 7216 send it SIGUSR2
received SIGUSR2
$ kill 7216 now send it SIGTERM
[1]+ Terminated ./a.out