- 论坛徽章:
- 2
|
4.4 信号处理
现在我们知道何时会产生信号,也知道如何发送信号,那么我们怎么处理它们呢?
signal函数
signal系统函数调用提供了一种最简单的范例。然而,由于C原形声明的缘故使它看起来比实际复杂。signal函数将一个给定的函数和一个特定的信号联系。这里是FreeBSD中的定义(和一个typedef一起):
typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);
第一个参数是目标信号,可以是上面列举的所有信号中的任何一个。func参数是一个指针,指向某个处理该信号的函数。这个处理信号函数带有一个int型参数,并应返回void。signal函数中的func参数也可以设定为下面的一些值:
SIG_IGN: 如果func参数被设置为SIG_IGN,该信号将被忽略。
SIG_DFL: 如果func参数被设置为SIG_DFL,该信号会按照确定行为处理。
sigaction函数
sigaction函数是一个比signal更通用的方案。第一个参数是目标信号。下一个名为act的参数(指向)sigaction结构,该结构包含一些用于信号处理的信息。最后一个参数oact是一个指针,指向一个可以存储上一次设置信号处理的信息的地方。
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
sigaction结构有下面这些个成员:
这个结构成员是一个指向函数的指针,该函数带有一个简单的整形参数,并返回(void)。这与signal函数的func参数相同,也可以被设置为SIG_IGN和SIG_DFL,并且与调用signal得到的效果也一样。
void (*sa_sigaction)(int, siginfo_t *, void *);
该结构成员是一个指向函数的指针,返回(void)并需要三个参数。这些参数依次为:一个整形参数指定信号发送;一个指向siginfo_t结构的指针用来保存关于信号的信息;最后一个也是一个指针,指向信号交付时的特定上下文(context)空间。
该结构成员是一个位掩码(bitwise mask),用来指示信号交付时哪些信号会被阻塞。阻塞SIGKILL和SIGSTOP信号的做法会被忽略。接下来,被阻塞的信号将被推迟,直到它们被开启(unblock)。参见sigprocmask获得更多关于全局掩码(global masks)的信息。
该数据成员是一个拥有下面这些标志的位掩码:
SA_NOCLDSTOP: 如果SA_NOCLDSTOP位被置位并且目标信号是SIGCHLD,除非子进程退出,而在子进程停止(stop)时父进程将不会收到通知。
SA_NOCLDWAIT: SA_NOCLDWAIT标志会阻止子进程成为僵尸进程。在目标信号是SIGCHLD的时候使用。如果进程设置了这个标志,接着调用某个wait系统调用,进程将被阻塞直到子进程全部终止,最后返回-1(译注:此处在APUE2ed中的解释是返回1),设置errno全局变量为ECHILD。
SA_ONSTACK: 一些时候需要在特定的堆栈上进行信号的处理。sigaction系统调用提供了这个方式。如果该位被置位,那么信号将会被交付到指定的堆栈上。
SA_NODEFER: 如果SA_NODEFER位被置位,那么当前信号正被处理时,系统不会屏蔽该信号以后的交付。
SA_RESETHAND: 如果SA_RESETHAND被置位,一旦信号被交付,信号处理句柄将被置为SIG_DEF。
SA_SIGINFO: 被置位时,由结构体sigaction 的成员sa_sigaction指向的函数被使用。注意:使用SIG_IGN或SIG_DFL时不应该设置这个标志。成功调用sigaction之后,返回0或-1,并且将error设置成相关错误值。
4.5信号掩码(阻塞与开启信号)
进程可以阻塞或设置某个信号。一旦该信号被阻塞,关于它的交付将被推迟,直到进程重新开启它。在这样的情况下是非常有用的:进程进入代码中某个部分,不能被中断但仍希望可以接受、处理可能丢失的信号。可靠交付信号的能力直到4.2BSD引入之后(不久被SVR3采用),操作系统才拥有该能力。
随着可靠信号的出现,信号的生命和交付(life and delivery)都有所改变。信号可以在之前产生和交付。现在,一旦信号是挂起的(pending),进程可以在接收它之前决定怎么处理。进程可能会去处理它,也可能设置为缺省行为,或者丢弃信号
注意:如果许多信号都挂起,系统将会首先交付会改变进程状态的信号,例如SIGBUS。
sigprocmask
任何进程可以使用sigprocmask函数来阻塞信号。语法如下:
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
sigprocmask函数会修改或检查(modify or examine)当前信号掩码。当set参数不是null的时候,sigprocmask的行为和第一个参数how有关。函数行为和相关意义列举如下:
SIG_BLOCK: 在set参数中指定的信号被阻塞,并且添加进阻塞信号列表。
SIG_UNBLOCK: 在set参数中指定的信号会从信号掩码中移除。
SIG_SETMASK: set参数将完全替代当前信号掩码。如果oset参数不为null,则会被设置为前一个信号掩码。如果set值是null,how参数被忽略并且信号掩码保持不变。所以,为了检查信号掩码,我们可以将传入set null值,oset为非null值来调用sigprocmask函数。一旦掩码得到之后,你可能需要对他进行检查或操作。可以使用下面的过程(routine)。注意当前这些过程是宏的实现。 - int sigemptyset(sigset_t *set)
复制代码
如果调用这个过程,set参数将被初始化指向一个空信号集。
- int sigfillset(sigset_t *set)
复制代码
如果调用这个过程,set参数将被初始化指向一个包括所有信号的信号集。
- int sigaddset(sigset_t *set, int signo)
复制代码
如果调用这个过程,signo指定的信号将被添加进set参数指定的信号集。
- int sigdelset(sigset_t *set, int signo)
复制代码
如果调用这个过程,signo指定的信号将从set参数指定的信号集中移除。
- int sigismember(const sigset_t *set, int signo)
复制代码
如果调用这个过程,如果由signo指定的信号存在于set参数指定的信号集中时,返回1,否则返回0。
- int sigpending(sigset_t *set);
复制代码
进程可以使用sigpending函数去查出当前那些信号被挂起。sigpending函数会返回一个包含所有挂起信号的掩码。该掩码可以使用上面介绍的过程去检查。sigpending成功时返回0,否则返回-1,并且设置errno为相应错误值。
(怎么还有25%呢![](static/image/smiley/default/em16.gif) )
[ 本帖最后由 gvim 于 2006-2-20 11:24 编辑 ] |
|