阅读《Unix环境高级编程》P283页 10.15处的体会。(错误之处,望大家批评指正)
本文通过几个实验说明sigjmp longjmp 和 sigsetjmp siglongjmp的区别。
实验一:执行信号X(任意信号)处理程序时,X信号会被自动加入到信号屏蔽字。信号处理程序执行完毕,信号屏蔽字会恢复原来的。
1 #include <stdio.h>
2 #include "apue.h"
3 #include <signal.h>
4 #include <setjmp.h>
5
6
7 void deal_sig(int a)
8 {
9 sigset_t sigpend;
10 sigset_t sigmask;
11 sleep(5);//延时等待SIGQUIT再次发生
12 sigpending(&sigpend);
13 sigprocmask(0,NULL,&sigmask);
14
15 if(sigismember(&sigpend,SIGQUIT))
16 {
17 printf("SIGQUIT is pending\n");
18 }
19 else
20 {
21 printf("SIGQUIT is not pending\n");
22 }
23
24 if(sigismember(&sigmask,SIGQUIT))
25 {
26 printf("SIGQUIT is in sigmask\n");
27 }
28 else
29 {
30 printf("SIGQUIT is not in sigmask\n");
31 }
32
33 }
34
35 int main()
36 {
37 int sleep_ret;
38 sigset_t sigmask;
39 if(signal(SIGQUIT,deal_sig)==SIG_ERR)
40 {
41 printf("signal error\n");
42 exit(1);
43 }
44 sleep_ret = sleep(5);//延时等待信号发生
45
46
47 sigprocmask(0,NULL,&sigmask);
48 if(sigismember(&sigmask,SIGQUIT))
49 {
50 printf("main : SIGQUIT is in sigmask\n");
51 }
52 else
53 {
54 printf("main : SIGQUIT is not in sigmask\n");
55 }
56
57 printf("sleep_ret = %d\n",sleep_ret);
58 exit(0);
59 }
运行结果
^\^\SIGQUIT is pending
SIGQUIT is in sigmask
SIGQUIT is not pending
SIGQUIT is in sigmask
main : SIGQUIT is not in sigmask
sleep_ret = 4
第一SIGQUIT信号发生时,正在执行信号处理程序,此时再次发生该信号,信号处于未决态,信号被自动加入信号屏蔽字。
信号处理程序执行完,第二次的信号开始处理,信号又被加入信号屏蔽字,但是没有第三次发生SIGQUIT,因此没有SIGQUIT在未决态。
main:是主函数打印的,信号处理程序返回,检查信号屏蔽字,发现,SIGQUIT不在信号屏蔽字。(证明信号处理程序返回,自动恢复了信号屏蔽字。)
信号处理程序返回,sleep不会继续睡眠,直接返回剩余的时间,因此sleep_ret=4。
实验二:如果用longjmp跳出信号处理程序,进程的信号屏蔽字会发生什么。不同平台处理方式不同。
Linux3.2.0和Solaris不会恢复信号屏蔽字,FreeBSD8.0,MacOS X 10.6.8会保存和恢复信号屏蔽字。
测试环境Ubantu
1 #include <stdio.h>
2 #include "apue.h"
3 #include <signal.h>
4 #include <setjmp.h>
5
6 static jmp_buf jmpbuf;
7
8 void deal_sig(int a)
9 {
10 sigset_t sigpend;
11 sigset_t sigmask;
12 sleep(5);
13 sigpending(&sigpend);
14 sigprocmask(0,NULL,&sigmask);
15
16 if(sigismember(&sigpend,SIGQUIT))
17 {
18 printf("SIGQUIT is pending\n");
19 }
20 else
21 {
22 printf("SIGQUIT is not pending\n");
23 }
24
25 if(sigismember(&sigmask,SIGQUIT))
26 {
27 printf("SIGQUIT is in sigmask\n");
28 }
29 else
30 {
31 printf("SIGQUIT is not in sigmask\n");
32 }
33 longjmp(jmpbuf,1);
34 }
35
36 int main()
37 {
38 sigset_t sigmask;
39 sigset_t sigpend;
40 if(signal(SIGQUIT,deal_sig)==SIG_ERR)
41 {
42 printf("signal error\n");
43 exit(1);
44 }
45 while(setjmp(jmpbuf)==0);
46
47 sigprocmask(0,NULL,&sigmask);
48 if(sigismember(&sigmask,SIGQUIT))
49 {
50 printf("main : SIGQUIT is in sigmask\n");
51 }
52 else
53 {
54 printf("main : SIGQUIT is not in sigmask\n");
55 }
56 sigpending(&sigpend);
57 if(sigismember(&sigpend,SIGQUIT))
58 {
59 printf("main : SIGQUIT is pending\n");
60 }
61 else
62 {
63 printf("main : SIGQUIT is not pending\n");
64 }
65
66 exit(0);
67 }
运行结果
^\^\SIGQUIT is pending
SIGQUIT is in sigmask
main : SIGQUIT is in sigmask
main : SIGQUIT is pending
第一次发生信号,进入信号处理程序,SIGQUIT自动加入信号屏蔽字,第二次发生的信号处于未决态。
信号处理程序返回,SIGQUIT还在屏蔽字中,第二次发生的信号还是未决态。
实验三:实验二的sigjmp longjmp 换成 sigsetjmp siglongjmp
1 #include <stdio.h>
2 #include "apue.h"
3 #include <signal.h>
4 #include <setjmp.h>
5
6 static jmp_buf jmpbuf;
7
8 void deal_sig(int a)
9 {
10 sigset_t sigpend;
11 sigset_t sigmask;
12 sleep(5);
13 sigpending(&sigpend);
14 sigprocmask(0,NULL,&sigmask);
15
16 if(sigismember(&sigpend,SIGQUIT))
17 {
18 printf("SIGQUIT is pending\n");
19 }
20 else
21 {
22 printf("SIGQUIT is not pending\n");
23 }
24
25 if(sigismember(&sigmask,SIGQUIT))
26 {
27 printf("SIGQUIT is in sigmask\n");
28 }
29 else
30 {
31 printf("SIGQUIT is not in sigmask\n");
32 }
33 siglongjmp(jmpbuf,1);
34 }
35
36 int main()
37 {
38 sigset_t sigmask;
39 sigset_t sigpend;
40 if(signal(SIGQUIT,deal_sig)==SIG_ERR)
41 {
42 printf("signal error\n");
43 exit(1);
44 }
45 while(sigsetjmp(jmpbuf,1)==0);
46
47 sigprocmask(0,NULL,&sigmask);
48 if(sigismember(&sigmask,SIGQUIT))
49 {
50 printf("main : SIGQUIT is in sigmask\n");
51 }
52 else
53 {
54 printf("main : SIGQUIT is not in sigmask\n");
55 }
56 sigpending(&sigpend);
57 if(sigismember(&sigpend,SIGQUIT))
58 {
59 printf("main : SIGQUIT is pending\n");
60 }
61 else
62 {
63 printf("main : SIGQUIT is not pending\n");
64 }
65
66 exit(0);
67 }
运行结果1:sigsetjmp(jmpbuf,1)自动恢复了信号屏蔽字。
^\^\SIGQUIT is pending
SIGQUIT is in sigmask
SIGQUIT is not pending
SIGQUIT is in sigmask
main : SIGQUIT is not in sigmask
main : SIGQUIT is not pending
运行结果2:sigsetjmp(jmpbuf,0)第二个参数填0,没有自动恢复信号屏蔽字。(非零会恢复)
^\^\SIGQUIT is pending
SIGQUIT is in sigmask
main : SIGQUIT is in sigmask
main : SIGQUIT is pending
总结:sigjmp longjmp 和 sigsetjmp siglongjmp比较
1、信号处理程序正常结束,会恢复原来的信号屏蔽字。
2、在Linux3.2.0中,longjmp跳出信号处理程序,不会恢复原来的信号屏蔽字。
3、siglongjmp的第二个参数非零,恢复信号屏蔽字,为0则不恢复。