测试代码
void sig_int(int);
void sig_usr(int);
int main(){
print_mask("at the beginning:");
sigset_t new_mask,old_mask,wait_mask;
//install signal SIGINT handler
if(signal(SIGINT,sig_int) == SIG_ERR){
//signal error
}
//install signal SIGUSR1 SIGUSR2 SIGALRM handler
if(signal(SIGUSR1,sig_usr) == SIG_ERR){
//signal error
}
if(signal(SIGUSR2,sig_usr) == SIG_ERR){
//signal error
}
if(signal(SIGALRM,sig_usr) == SIG_ERR){
//signal error
}
//reset signal mask to wait_mask instead of adding wait_mask to original mask and wait for a signal to interrupt it and continue the program
//test the signal mask before the sigsuspend returns(caught a signal and being exectuted the handler)
sigemptyset(&wait_mask);
sigaddset(&wait_mask,SIGUSR1);
sigaddset(&wait_mask,SIGUSR2);
sigaddset(&wait_mask,SIGALRM);
//SIGUSR1, SIGUSR2 and SIGUSR2 are blocked, all signals except those are allowed to interrupt the suspend and makes the sigsuspend function return
//when program is being suspended by function sigsuspend, the signal which is not blocked will be delivered and handled, and the current signal mask includes wait_mask and itself, the sigsuspend will return -1 after the handling
if(sigsuspend(&wait_mask) != -1){
//sigsuspend error
}
else{
printf("sigsuspend returns\n");
}
// // after the sigsuspend returns, the signal mask will restore to what is was before the sigsuspend was executed
// // check the signal mask
print_mask("at the end:");
exit(0);
}
//the signal which is being handled by its handler will be added to the signal mask automatically to prevent being interrupted by the same signal
//SIGINT handler
void sig_int(int signo){
print_mask("\nSIGINT is being handled and the signal mask is"); //check the siganl mask
}
//SIGUSR1, SIGUSR2 and SIGALRM handler
void sig_usr(int signo){
if(signo == SIGUSR1)
print_mask("\nSIGUSR1 is being handled and the signal mask is"); //check the siganl mask
if(signo == SIGUSR2)
print_mask("\nSIGUSR2 is being handled and the signal mask is"); //check the siganl mask
if(signo == SIGALRM)
print_mask("\nSIGALRM is being handled and the signal mask is"); //check the siganl mask
}
代码说明: sigsuspend
设置屏蔽了三个不同信号, 分别是SIGUSR1
, SIGUSR2
和SIGALRM
测试过程
make生成可执行文件sigsuspend, 用shell命令./sigsuspend &
使可执行文件在后台运行, shell返回结果为
可以看到, 25661为该进程的进程号, 用kill
命令向该进程以此发送SIGUSR1
, SIGUSR2
, SIGALRM
, SIGINT
四个信号
发送完信号后, shell的返回结果如果下:
可以看到, sigsuspend函数是在处理完被屏蔽的三个信号SIGUSR1
, SIGUSR2
和SIGALRM
后才返回的, 所以被sigsuspend函数屏蔽的信号是在sigsuspend返回前被处理的
被屏蔽的三个信号SIGUSR1
, SIGUSR2
和SIGALRM
的处理过程中信号屏蔽字会跟着改变, 处理的顺序会不会跟信号的发送顺序有关, 所以我改变信号的发送顺序为SIGALRM
, SIGUSR2
, SIGUSR1
, SIGINT
, 得到shell的返回结果如下:
可以看到, 对于屏蔽的三个信号SIGALRM
, SIGUSR2
和SIGUSR1
的处理过程与前一个信号发送顺序返回的的结果一模一样, 所以可以猜测对于屏蔽的三个信号SIGALRM
, SIGUSR2
和SIGUSR1
的处理过程是按照一定的顺序的, 会不会跟信号集添加信号的次序有关, 所以我改变信号集的添加顺序为如下
sigaddset(&wait_mask,SIGALRM);
sigaddset(&wait_mask,SIGUSR2);
sigaddset(&wait_mask,SIGUSR1);
再次按顺序SIGUSR1
, SIGUSR2
, SIGALRM
, SIGINT
和顺序SIGALRM
, SIGUSR2
, SIGUSR1
, SIGINT
两种顺序发送信号, 得到的结果都是:
可以看到, 信号的处理顺序和之前几次都一模一样, 所以可以推断, 被屏蔽的信号的处理顺序跟信号集添加的顺序和信号的发送顺序都无关, 是按照特定的顺序, 推测可能是跟信号屏蔽字的本身的位图有关
结论
- 被sigsuspend函数屏蔽的信号是在sigsuspend返回前被处理的
- 被sigsuspend函数屏蔽的信号的处理顺序跟信号集添加的顺序和信号的发送顺序都无关, 是按照特定的顺序, 又已知屏蔽字的定义是
typedef unsigned long sigset_t;
, 所以推测可能是跟信号屏蔽字的本身的结构(可能是位图)有关, 假设信号屏蔽字中每一位对应一种信号, 屏蔽字中1为屏蔽对应的信号, 0为不屏蔽对应信号, 所以推测被屏蔽的信号的处理过程大概是, 检查屏蔽字中第一个1, 解除屏蔽, 即将屏蔽位置0, 看是否有对应的信号递送, 如果有, 将屏蔽位置1并执行相应的信号处理程序, 处理完又将对应的屏蔽位置0, 接着检查屏蔽字中下一个1, 解除屏蔽检查是否有这个屏蔽位对应的信号递送, 如果有则置1并处理, 处理完又置0, 接着检查屏蔽字中的下一个1, 以此类推, 直到屏蔽字中没有1, 处理结束