您的位置:首页 > 编程语言

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

2014-11-09 17:18 393 查看
前面《异常处理》介绍了两个关于用于非局部跳转的 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


参考资料:

《UNIX高级环境编程》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: