从自定义信号处理程序调用原始信号处理程序

Call original signal handler from custom signal handler

主题说明了一切。

我希望能够在完成清理后将某些信号推迟到默认的 OS 信号处理程序。

例如如果收到 SIGINT,我想在自定义清理例程后终止程序,并希望为此使用标准 OS 例程,而不是 callind _exit() 或其他任何例程。

我想我可以在用 sigaction() 覆盖它之前以某种方式获得对原始信号处理程序的引用,但我不知道该怎么做。

这是我目前的代码:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

volatile sig_atomic_t sigterm_flag = 0;
volatile sig_atomic_t sighup_flag = 0;
volatile sig_atomic_t sig_default_flag = 0;

void sigact(int signum, siginfo_t *siginfo, void *ucontext)
{
    switch(signum)
    {
    case SIGTERM:
        sigterm_flag = 1;
        break;
    case SIGHUP:
        sighup_flag = 1;
        break;
    default:
        sig_default_flag = 1;
        break;
    }
}

int main(void)
{
    struct sigaction sa;

    sa.sa_sigaction = sigact;
    sa.sa_flags = SA_SIGINFO;
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);

    while (1) {
        if (sigterm_flag == 1) {
            sigterm_flag = 0;
            printf("SIGTERM caught.\n");
        }
        if (sighup_flag == 1) {
            sighup_flag = 0;
            printf("SIGHUP caught.\n");
        }
        if (sig_default_flag == 1) {
            sig_default_flag = 0;
            printf("Other signal caught.\n");
        }
        sleep(1);
    }

    return 0;
}

编辑:

根据 tuxlike in answer

的建议解决了挑战

这是最终代码:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

volatile sig_atomic_t sigterm_flag = 0;
volatile sig_atomic_t sighup_flag = 0;
volatile sig_atomic_t sigint_flag = 0;
volatile sig_atomic_t sig_default_flag = 0;

void sigact(int signum, siginfo_t *siginfo, void *ucontext)
{
    switch(signum)
    {
    case SIGTERM:
        sigterm_flag = 1;
        break;
    case SIGHUP:
        sighup_flag = 1;
        break;
    case SIGINT:
        sigint_flag = 1;
        break;
    default:
        sig_default_flag = 1;
        break;
    }
}

int main(int argc, char *argv[])
{
    struct sigaction sa;
    struct sigaction sa_default;

    sigemptyset(&sa.sa_mask);
    sa.sa_sigaction = sigact;
    sa.sa_flags = SA_SIGINFO;

    sigemptyset(&sa_default.sa_mask);
    sa_default.sa_handler = SIG_DFL;
    sa_default.sa_flags = 0;

    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);

    printf("Started %s as PID %ld\n", argv[0], (long int)getpid());

    while (1) {
        if (sigterm_flag == 1) {
            sigterm_flag = 0;
            printf("SIGTERM caught.\n");
        }
        if (sighup_flag == 1) {
            sighup_flag = 0;
            printf("SIGHUP caught.\n");
        }
        if (sigint_flag == 1) {
            sigint_flag = 0;
            printf("\nSIGINT caught.\n");
            sigaction(SIGINT, &sa_default, NULL);
            raise(SIGINT);
        }
        if (sig_default_flag == 1) {
            sig_default_flag = 0;
            printf("Other signal caught.\n");
        }
        sleep(1);
    }

    return 0;
}

(请注意,您的信号操作结构初始化中缺少 sigemptyset(&sa.sa_mask);。这是一种常见的推荐做法,最初执行 memset(&sa, 0, sizeof sa); 以将所有(甚至填充)初始化为 all-zeros, 首先。)

根本没有用于默认信号处理程序操作的用户空间函数,默认处理发生在内核中。

您可以做的是使用 sigaction() to reset the default action (sa.sa_handler = SIG_DFL; sa.sa_flags = 0;), then re-raise the signal using raise(signum) 和处理程序中的 return。

sigaction()raise() 都是 async-signal safe,因此完全可以在信号处理程序中使用。