当你看到这里的时候一定对于信号有了一定的了解,但是还是做一点简单的铺垫比较好。
1.每个进程收到的信号都是由内核发送,内核处理的。
2.内核通过读取未决信号集来判断信号是否应该被处理,信号屏蔽字(mask)可以影响未决信号集。
3.Linux内核的进程控制块PCB是一个结构体,task_struct, 除了包含进程id,状态,工作目录,用户id,组id,文件描述符表,还包含了信号相关的信息,主要指阻塞信号集和未决信号集。
4.阻塞信号集(信号屏蔽字): 将某些信号加入集合,对他们设置屏蔽,当屏蔽x信号后,再收到该信号,该信号的处理将推后(解除屏蔽后)
5.未决信号集:
1. 信号产生,未决信号集中描述该信号的位立刻翻转为1,表信号处于未决状态。当信号被处理对应位翻转回为0。这一时刻往往非常短暂。
2. 信号产生后由于某些原因(主要是阻塞)不能抵达。这类信号的集合称之为未决信号集。在屏蔽解除前,信号一直处于未决状态。
下面进入主题
1.
我们可以通过自己定义的信号集来影响系统中的阻塞信号集,阻塞信号集影响未决信号集从而达到对信号的控制操作。
但是我们如何用自己定义的信号集来影响阻塞信号集呢?有如下函数可以使用
2.sigprocmask函数
用来屏蔽信号、解除屏蔽也使用该函数。其本质,读取或修改进程的信号屏蔽字(PCB中)
严格注意,屏蔽信号:只是将信号处理延后执行(延至解除屏蔽);而忽略表示将信号丢处理。
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); 成功:0;失败:-1,设置errno
参数:
set:传入参数,是一个位图,set中哪位置1,就表示当前进程屏蔽哪个信号。
oldset:传出参数,保存旧的信号屏蔽集。
how参数取值: 假设当前的信号屏蔽字为mask
1. SIG_BLOCK: 当how设置为此值,set表示需要屏蔽的信号。相当于 mask = mask|set
2. SIG_UNBLOCK: 当how设置为此,set表示需要解除屏蔽的信号。相当于 mask = mask & ~set
3. SIG_SETMASK: 当how设置为此,set表示用于替代原始屏蔽及的新屏蔽集。相当于 mask = set若,调用sigprocmask解除了对当前若干个信号的阻塞,则在sigprocmask返回前,至少将其中一个信号递达。
3.内核中的阻塞信号集没办法读取不过系统提供了可以读取未决信号集的函数,因为阻塞信号集可以影响未决信号集从而也得到阻塞信号集
sigpending函数
读取当前进程的未决信号集
int sigpending(sigset_t *set); set传出参数。 返回值:成功:0;失败:-1,设置errno
下面举个小例子,打印未决信号集(其中我将3号信号设置为阻塞状态,所以当我发出3号信号的时候内核就不处理而是阻塞住,注意3号信号是通过按键产生的Ctrl \)
4.信号捕捉函数
sigaction函数
修改信号处理动作(通常在Linux用其来注册一个信号的捕捉函数)
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); 成功:0;失败:-1,设置errno
参数:
act:传入参数,新的处理方式。
oldact:传出参数,旧的处理方式
struct sigaction结构体
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);//忽略
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);//暂时忽略
};
sa_restorer:该元素是过时的,不应该使用,POSIX.1标准将不指定该元素。(弃用)
sa_sigaction:当sa_flags被指定为SA_SIGINFO标志时,使用该信号处理程序。(很少使用)
重点
① sa_handler:指定信号捕捉后的处理函数名(即注册函数)。也可赋值为SIG_IGN表忽略 或 SIG_DFL表执行默认动作
② sa_mask: 调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意:仅在处理函数被调用期间屏蔽生效,是临时性设置。
③ sa_flags:通常设置为0,表使用默认属性。
再次强调:次函数重点是参数的结构体成员中的东西!注意mask是在信号捕捉函数执行期间所屏蔽的信号集,在这个信号集中的信号在函数执行期间如果被发送过来,则屏蔽这些信号,还有就是flag在函数捕捉函数执行的期间,引起捕捉函数的信号再次过来的话,这个信号也会被屏蔽。统统等函数执行完在处理。
信号捕捉特性
1. 进程正常运行时,默认PCB中有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号。当注册了某个信号捕捉函数,捕捉到该信号以后,要调用该函数。而该函数有可能执行很长时间,在这期间所屏蔽的信号不由内核来指定。而是用sa_mask来指定。调用完信号处理函数,再恢复为内核。
2. XXX信号捕捉函数执行期间,XXX信号自动被屏蔽。
3. 阻塞的常规信号不支持排队,产生多次只记录一次。(后32个实时信号支持排队)
在信号函数执行期间,内核的判定信号的信号集不是由内核提供的信号屏蔽字取影响未决信号集决定,而是由我们传进去的mask影响未决信号集决定!当捕捉函数执行结束又由内核的信号屏蔽字决定。如果在捕捉函数执行期间没有屏蔽某信号,则当这个信号发过来的时候直接处理这个信号,如果被捕捉信号和其他被屏蔽信号一起发送过来,则再次执行捕捉信号,然后在执行其他信号。
关于信号捕捉的一些函数就简单的介绍完了