《unix环境高级编程》信号——sigsetjmp 函数和 siglongjmp 函数

来源:互联网 发布:人机界面数据记录 编辑:程序博客网 时间:2024/06/09 20:15

  前面《异常处理》介绍了两个关于用于非局部跳转的 setjmp 和 longjmp 函数,在信号处理程序中经常调用 longjmp 函数以返回到程序的主循环中,而不是从该处理程序返回。但是调用 longjmp 有一个问题,当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被自动加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断该信号处理程序。POSIX.1 并没有说明 setjmp 和 longjmp 对信号屏蔽字的作用,而是定义了两个新函数 sigsetjmp 和siglongjmp。在信号处理程序进行非局部转移时应该使用这两个函数。

        在 sigsetjmp 中增加了一个参数,如果 savemask 非0,则 sigsetjmp 在 env 中保存进程的当前信号屏蔽字。调用 siglongjmp 时,如果带非0savemask 的 sigsetjmp 调用已经保存了 env,则 siglongjmp 从其中恢复保存的信号屏蔽字。

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <setjmp.h>  
  2. int sigsetjmp(sigjmp_buf env, int savemask); //若直接调用则返回0,若从siglongjmp调用返回则返回非0值。  
  3. void siglongjmp(sigjmp_buf env, int val);  

测试程序:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include  "pr_mask.h"   /* include the function of pr_mask() */  
  2. #include <setjmp.h>  
  3. #include <time.h>  
  4.   
  5. static void sig_usr1(int), sig_alrm(int);  
  6. static sigjmp_buf   jmpbuf;  
  7. static volatile sig_atomic_t canjump;  
  8.   
  9. int main(void)  
  10. {  
  11.     if(signal(SIGUSR1, sig_usr1) == SIG_ERR)  
  12.         err_sys("signal(SIGUSR1) error");  
  13.     if(signal(SIGALRM, sig_alrm) == SIG_ERR)  
  14.         err_sys("signal(SIGALRM) error");  
  15.     pr_mask("starting main: ");  
  16.   
  17.     if(sigsetjmp(jmpbuf, 1))  
  18.     {  
  19.         pr_mask("ending main: ");  
  20.         exit(0);  
  21.     }  
  22.     canjump = 1;  
  23.     for(;;)  
  24.         pause();  
  25. }  
  26. static void sig_usr1(int signo)  
  27. {  
  28.     time_t starttime;  
  29.     if(0 == canjump)  
  30.         return;  
  31.     pr_mask("starting sig_usr1: ");  
  32.     alarm(3);  
  33.     starttime = time(NULL);  
  34.   
  35.     for(; ;)  
  36.         if(time(NULL) > starttime+5)  
  37.             break;  
  38.     pr_mask("finishing sig_usr1: ");  
  39.     canjump = 0;  
  40.     siglongjmp(jmpbuf,1);  
  41. }  
  42.   
  43. static void sig_alrm(int signo)  
  44. {  
  45.     pr_mask("in sig_alrm: ");  
  46. }  
输出结果:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. $ ./sigsetjmp &  
  2. [1] 15206  
  3. starting main:   
  4. $ kill -USR1 15206  
  5. starting sig_usr1:   
  6. $ in sig_alrm:   
  7. finishing sig_usr1:   
  8. ending main:   
  9.   
  10. [1]+  Done                    ./sigsetjmp  
其中打印函数如下:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #ifndef PR_MASK_H  
  2. #define PR_MASK_H  
  3. #include "apue.h"  
  4. #include <errno.h>  
  5.   
  6. void pr_mask(const char *str)  
  7. {  
  8.     sigset_t sigset;  
  9.     int errno_save;  
  10.   
  11.     errno_save = errno;  
  12.     if(sigprocmask(0, NULL, &sigset) < 0)  
  13.         err_sys("sigprocmask error");  
  14.   
  15.     printf("%s\n", str);  
  16.     if(sigismember(&sigset, SIGINT))  
  17.         printf("SIGINT\t");  
  18.     if(sigismember(&sigset, SIGQUIT))  
  19.         printf("SIGQUIT\t");  
  20.     if(sigismember(&sigset, SIGUSR1))  
  21.         printf("SIGUSR1\t");  
  22.     if(sigismember(&sigset, SIGALRM))  
  23.         printf("SIGALRM\t");  
  24. }  
  25. #endif  
0 0
原创粉丝点击