信号在内核中的表示:
信号在传递过程中有三个状态:执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态称为信号未决(Pending)。进程也可以选择阻塞(Block)某个信号,被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达动作。阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选一种处理动作。信号在内核中的表示如下图所示:
图中block表和pending表由位图形式存储信号状态,每个信号只有一bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这的“屏蔽”应该理解为阻塞而不是忽略。
信号处理函数:
int sigemptyset(sigset_t *set);
//初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含任何有效信号
int sigfillset(sigset_t *set);
//t初始化set所指向的信号集,使其中所有信号的对应bit置位有效,表示该信号集的有效信号包括系统支持的所有信号
int sigaddset(sigset_t *set, int signo);
//信号集中添加某种有效信号
int sigdelset(sigset_t *set, int signo);
//信号集中删除某种有效信号
int sigismember(const sigset_t *set, int signo);
//用于判断一个信号集的有效信号中是否包含某种信号
调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
返回值:若成功则为0,若出错则为-1
how参数:
1)SIG_BLOCK添加到当前信号屏蔽字的信号
2)SIG_UNBLOCK从当前信号屏蔽字中解除的信号
3)SIG_SETMASK设置当前信号屏蔽字为set所指向的值
int sigpending(sigset_t *set);
//sigpending读取当前进程的未决信号集,通过set参数传出。调⽤用成功则返回0,出错则返回 -1
验证pending表,修改pcb的pending表中的一个bit位,即发信号,下面这段代码中为Ctrl+c信号
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
void handler(int s)
{
if(s==SIGINT)
{
}else if(s==SIGQUIT)
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigprocmask(SIG_UNBLOCK, &set, NULL);
}
}
void print_set(sigset_t *set)
{
int i;
for(i=1; i<NSIG; i++)
{
if(sigismember(set,i))
{
printf("1");
}
else
{
printf("0");
}
}
printf("\n");
}
int main()
{
signal(SIGINT, handler);
signal(SIGQUIT, handler);
sigset_t bset,pset;
sigemptyset(&bset);//清空信号集
sigaddset(&bset, SIGINT);//将int信号加入信号集
sigprocmask(SIG_BLOCK, &bset, NULL);//将我们的值设置进内核
for(;;)
{
sigpending(&pset);//获得内核的未决信号集
print_set(&pset);
sleep(1);
}
}