c - 关于sigsetjmp的一些错误

标签 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:

那是没有信号。请帮助我。

最佳答案

我认为问题可能出在您使用 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: 
$

关于c - 关于sigsetjmp的一些错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8676459/

相关文章:

c++ - 查找 CPU 利用率和 CPU 周期

c - Linux 如何确定自定义信号处理程序的优先级?

c - 指定 RIDEV_NOLEGACY 时,Win32 原始输入会阻止输入区域设置切换

c - C 中的双端队列结构。 问题

python - 超时时杀死或终止子进程?

ruby - 是什么导致我的 Ruby `trap` block 出现这种死锁?

arrays - 一种比较峰值的算法 : are they in phase or not?

c++ - 如何使用 QProcess 通过 Ping 检测 "Network is Unreachable"?

linux - Auralise Audacity 注释/从点击时间列表生成音频点击轨道

c++ - 运行时而不是加载时出现符号查找错误