前面《异常处理》介绍了两个关于用于非局部跳转的 setjmp 和 longjmp 函数,在信号处理程序中经常调用 longjmp 函数以返回到程序的主循环中,而不是从该处理程序返回。但是调用 longjmp 有一个问题,当捕捉到一个信号时,进入信号捕捉函数,此时当前信号被自动加到进程的信号屏蔽字中。这阻止了后来产生的这种信号中断该信号处理程序。POSIX.1 并没有说明 setjmp 和 longjmp 对信号屏蔽字的作用,而是定义了两个新函数 sigsetjmp 和siglongjmp。在信号处理程序进行非局部转移时应该使用这两个函数。
在 sigsetjmp 中增加了一个参数,如果 savemask 非0,则 sigsetjmp 在 env 中保存进程的当前信号屏蔽字。调用 siglongjmp 时,如果带非0savemask 的 sigsetjmp 调用已经保存了 env,则 siglongjmp 从其中恢复保存的信号屏蔽字。
- #include <setjmp.h>
- int sigsetjmp(sigjmp_buf env, int savemask); //若直接调用则返回0,若从siglongjmp调用返回则返回非0值。
- void siglongjmp(sigjmp_buf env, int val);
测试程序:
- #include "pr_mask.h" /* include the function of pr_mask() */
- #include <setjmp.h>
- #include <time.h>
- static void sig_usr1(int), sig_alrm(int);
- static sigjmp_buf jmpbuf;
- static volatile sig_atomic_t canjump;
- int main(void)
- {
- if(signal(SIGUSR1, sig_usr1) == SIG_ERR)
- err_sys("signal(SIGUSR1) error");
- if(signal(SIGALRM, sig_alrm) == SIG_ERR)
- err_sys("signal(SIGALRM) error");
- pr_mask("starting main: ");
- if(sigsetjmp(jmpbuf, 1))
- {
- pr_mask("ending main: ");
- exit(0);
- }
- canjump = 1;
- for(;;)
- pause();
- }
- static void sig_usr1(int signo)
- {
- time_t starttime;
- if(0 == canjump)
- return;
- pr_mask("starting sig_usr1: ");
- alarm(3);
- starttime = time(NULL);
- for(; ;)
- if(time(NULL) > starttime+5)
- break;
- pr_mask("finishing sig_usr1: ");
- canjump = 0;
- siglongjmp(jmpbuf,1);
- }
- static void sig_alrm(int signo)
- {
- pr_mask("in sig_alrm: ");
- }
- $ ./sigsetjmp &
- [1] 15206
- starting main:
- $ kill -USR1 15206
- starting sig_usr1:
- $ in sig_alrm:
- finishing sig_usr1:
- ending main:
- [1]+ Done ./sigsetjmp
- #ifndef PR_MASK_H
- #define PR_MASK_H
- #include "apue.h"
- #include <errno.h>
- void pr_mask(const char *str)
- {
- sigset_t sigset;
- int errno_save;
- errno_save = errno;
- if(sigprocmask(0, NULL, &sigset) < 0)
- err_sys("sigprocmask error");
- printf("%s\n", str);
- if(sigismember(&sigset, SIGINT))
- printf("SIGINT\t");
- if(sigismember(&sigset, SIGQUIT))
- printf("SIGQUIT\t");
- if(sigismember(&sigset, SIGUSR1))
- printf("SIGUSR1\t");
- if(sigismember(&sigset, SIGALRM))
- printf("SIGALRM\t");
- }
- #endif