linux 当前处理信号自动屏蔽

在Linux系统中,当一个信号正在被处理时,内核会自动阻止该信号的再次触发,防止信号处理函数的嵌套执行。在信号处理函数返回后,信号的屏蔽状态会恢复到调用处理函数之前的状态。例如,SIGUSR1如果未被阻塞,处理后将恢复未阻塞状态;而SIGUSR2如果被阻塞,在处理后仍保持阻塞。通过示例代码可以观察到信号处理前后的mask变化,了解信号处理栈帧和sigreturn系统调用的角色。在某些情况下,如使用longjmp,可能无法正常恢复信号屏蔽,导致信号持续被阻塞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当某个信号被处理时(即正在执行信号处理handler),内核会自动阻塞该信号的再次传递(再次传递会导致信号处理handler的嵌套);
当信号处理返回后,内核会自动恢复该信号到调用信号处理handler之前的阻塞状态;


如信号SIGUSR1在调用handler之前未被阻塞,在调用handler时被阻塞,handler执行完后恢复未被阻塞状态;
信号SIGUSR2在调用handler之前被阻塞,在调用handler时仍被阻塞,handler执行完后恢复被阻塞状态;

 

Ref:

Advanced Programming in the UNIX Environment: Second Edition>>10.14. sigaction Function

Hence, we are guaranteed that whenever we are processing a given signal, another occurrence of that same signal is blocked until we're finished processing the first occurrence. Recall from Section 10.8 that additional occurrences of the same signal are usually not queued. If the signal occurs five times while it is blocked, when we unblock the signal, the signal-handling function for that signal will usually be invoked only one time.


用以下示例代码观察信号处理前、处理中、处理后的mask变化情况:

/* blockedinhandling.c */
  1 #include <stdio.h>
  2 #include <signal.h>
  3 #include <setjmp.h>
  4 
  5 #define prmask(sig)                                             \
  6 do {                                                            \
  7         int err;                                                \
  8         sigset_t omask;                                         \
  9         if ( err = sigprocmask(0, NULL, &omask) == 0 ) {        \
 10                 if (err = sigismember(&omask, sig) == 1 ) {     \
 11                         printf(#sig" is masked \n");            \
 12                 } else if ( err == 0) {                         \
 13                         printf(#sig" is not masked \n");        \
 14                 } else {                                        \
 15                         error("sigismember");                   \
 16                 }                                               \
 17         } else {                                                \
 18                 error("sigprocmask");                           \
 19         }                                                       \
 20 } while (0);
 21 
 22 #define BUFFSIZE 512
 23 #define error(err)              \
 24 do {                            \
 25         char buff[BUFFSIZE];    \
 26         snprintf(buff, BUFFSIZE, "[%s][%s][%d] %s \n", __FILE__, __FUNCTION__, __LINE__, err);  \
 27         perror(buff);           \
 28 } while (0);
 29 
 30 jmp_buf jmpbuf;
 31 
 32 void sigusr1(int signo)
 33 {
 34         printf("enter SIGUSR1 handler\n");
 35         prmask(SIGUSR1);
 36         printf("exit SIGUSR1 handler\n");
 37 }
 38 
 39 void sigusr2(int signo)
 40 {
 41         printf("enter SIGUSR2 handler\n");
 42         prmask(SIGUSR2);
 43         longjmp(jmpbuf, 0);
 44         printf("cannot here\n");
 45 }
 46 
 47 int main(int argc, char* argv[])
 48 {
 49         int err;
 50         struct sigaction act1, act2;
 51 
 52         act1.sa_handler = sigusr1;
 53         sigemptyset(&act1.sa_mask);
 54         act1.sa_flags = 0;
 55         act2.sa_handler = sigusr2;
 56         sigemptyset(&act2.sa_mask);
 57         act2.sa_flags = 0;
 58 
 59         if ( sigaction(SIGUSR1, &act1, NULL) != 0) {
 60                 error(NULL);
 61                 return -1;
 62         }
 63         if ( sigaction(SIGUSR2, &act2, NULL) != 0) {
 64                 error(NULL);
 65                 return -1;
 66         }
 67 
 68         printf("=========before kill========\n");
 69         prmask(SIGUSR1);
 70         prmask(SIGUSR2);
 71 
 72         printf("\n=========kill============\n");
 73         if ( kill(getpid(), SIGUSR1) != 0) {
 74                 error(NULL);
 75         }
 76         if ( setjmp(jmpbuf) == 0) {
 77                 if ( kill(getpid(), SIGUSR2) != 0) {
 78                         error(NULL);
 79                 }
 80                 sleep(1);
 81         }
 82 
 83         printf("\n=========after kill========\n");
 84         prmask(SIGUSR1);
 85         prmask(SIGUSR2);
 86 
 87         return 0;
 88 }

Makefile

all:
        gcc blockedinhandling.c -o blockedinhandling

 

[redhat@localhost signal]$ ./blockedinhandling 
=========before kill========
SIGUSR1 is not masked 
SIGUSR2 is not masked 

=========kill============
enter SIGUSR1 handler
SIGUSR1 is masked 
exit SIGUSR1 handler
enter SIGUSR2 handler
SIGUSR2 is masked 

=========after kill========
SIGUSR1 is not masked 
SIGUSR2 is masked 


内核在传递信号时,会设置信号处理栈帧并阻塞处理信号和sigaction.sa_mask中的信号;然后调用信号处理handler,handler返回时会调用内核设置在栈帧上的sigreturn系统调用,sigreturn会恢复因信号处理而做的信号屏蔽。
SIGUSR1的处理sigusr1正常返回,调用栈帧上的sigreturn系统调用,恢复因信号处理而做的信号屏蔽;即SIGUSR1是未被阻塞的。
SIGUSR2的处理sigusr2中使用了longjmp,所以不会正常返回,即不会调用栈帧上的sigreturn系统调用,也就不能恢复因信号处理而做的信号屏蔽;即SIGUSR2是被阻塞的。

信号传递见linux signal传递(处理)


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值