当某个信号被处理时(即正在执行信号处理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传递(处理)