sigsetjmp有些不对劲

时间:2011-12-30 05:30:48

标签: c linux signals

我正在阅读APUE,第10章。这是我的代码。

#include "apue.h"
#include <unistd.h>
#include <setjmp.h>
#include <time.h>
#include <errno.h>

static void sig_usr1(int), sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;

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");
    //print signal.
    pr_mask("Starting main: ");
    if(sigsetjmp(jmpbuf, 1)) {
        pr_mask("End main: ");
        exit(0);
    }
    canjmp = 1;
    for(;;)
        pause();
}

static void
sig_usr1(int signo)
{
    time_t starttime;

    if(canjmp == 0) {
        return;
    }

    pr_mask("starting sig_usr1: ");
    alarm(3);
    starttime = time(NULL);
    for(;;) 
        if(time(NULL) > starttime + 5)
            break;
    pr_mask("finishing sig_usr1: ");
    canjmp = 0;
    siglongjmp(jmpbuf, 1);
}

static void
sig_alrm(int signo)
{
    pr_mask("in sig_arlm: ");
}

void
pr_mask(const char *str)
{
    sigset_t    sigset;
    int         errno_save;

    errno_save = errno;     /* we can be called by signal handlers */
    if (sigprocmask(0, NULL, &sigset) < 0)
        err_sys("sigprocmask error");

    printf("%s", str);
    if (sigismember(&sigset, SIGUSR1))  printf("SIGUSR1 ");
    if (sigismember(&sigset, SIGALRM))  printf("SIGALRM ");
    /* remaining signals can go here  */

    printf("\n");
    errno = errno_save;
}

我认为输出会是这样的:

Starting main:
starting sig_usr1: SIGUSR1
in sig_alrm: SIGUSR1 SIGALRM
finishing sig_usr1: SIGUSR1
End main:

但似乎有些不对劲,这实际上是我的输出:

Starting main:
starting sig_usr1: 
in sig_alrm: 
finishing sig_usr1: 
End main:

这不是信号。请帮帮我。

1 个答案:

答案 0 :(得分:1)

我认为问题可能是您使用signal()而不是sigaction()来设置信号处理。并且signal()不会屏蔽任何其他信号 - 因此没有信号显示为被阻止。我修改了您的代码,如下所示,根据是否有任何参数使用signal()sigaction()

#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

typedef void (*Handler)(int);
static void sig_usr1(int), sig_alrm(int);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;
static void pr_mask(const char *str);

static void err_sys(const char *str)
{
    int errnum = errno;
    fprintf(stderr, "%s (%d: %s)\n", str, errnum, strerror(errnum));
    exit(1);
}

static void set_sigaction(int signum, Handler handler)
{
    struct sigaction nact;
    nact.sa_handler = handler;
    sigfillset(&nact.sa_mask);
    //sigemptyset(&nact.sa_mask);
    nact.sa_flags = 0;
    if (sigaction(signum, &nact, 0) != 0)
        err_sys("Failed to set signal handling");
}

int 
main(int argc, char **argv)
{
    printf("PID = %u\n", (unsigned)getpid());
    if (argc > 1)
    {
        if (signal(SIGUSR1, sig_usr1) == SIG_ERR)
            err_sys("signal(SIGUSR1) error");
        if (signal(SIGALRM, sig_alrm) == SIG_ERR)
            err_sys("signal(SIGALRM) error");
    }
    else
    {
        set_sigaction(SIGUSR1, sig_usr1);
        set_sigaction(SIGALRM, sig_alrm);
    }
    //print signal.
    pr_mask("Starting main: ");
    if (sigsetjmp(jmpbuf, 1)) {
        pr_mask("End main: ");
        exit(0);
    }
    canjmp = 1;
    for (;;)
        pause();
}

static void
sig_usr1(int signo)
{
    time_t starttime;

    if (canjmp == 0) {
        return;
    }

    pr_mask("starting sig_usr1: ");
    alarm(3);
    starttime = time(NULL);
    for (;;) 
        if (time(NULL) > starttime + 5)
            break;
    pr_mask("finishing sig_usr1: ");
    canjmp = 0;
    siglongjmp(jmpbuf, 1);
}

static void
sig_alrm(int signo)
{
    pr_mask("in sig_arlm: ");
}

void
pr_mask(const char *str)
{
    sigset_t    sigset;
    int         errno_save;

    errno_save = errno;     /* we can be called by signal handlers */
    if (sigprocmask(0, NULL, &sigset) < 0)
        err_sys("sigprocmask error");

    printf("%s", str);
    if (sigismember(&sigset, SIGUSR1))  printf("SIGUSR1 ");
    if (sigismember(&sigset, SIGALRM))  printf("SIGALRM ");
    /* remaining signals can go here  */

    printf("\n");
    errno = errno_save;
}

使用当前的XCode(4.2?)在MacOS X 10.7.2上运行,我得到(例如):

$ ./sigtest
PID = 11066
Starting main: 
starting sig_usr1: SIGUSR1 SIGALRM 
finishing sig_usr1: SIGUSR1 SIGALRM 
in sig_arlm: SIGUSR1 SIGALRM 
End main: 
$ ./sigtest 1
PID = 11067
Starting main: 
starting sig_usr1: SIGUSR1 
in sig_arlm: SIGUSR1 SIGALRM 
finishing sig_usr1: SIGUSR1 
End main: 
$