从自定义信号处理程序调用原始信号处理程序
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,因此完全可以在信号处理程序中使用。
主题说明了一切。
我希望能够在完成清理后将某些信号推迟到默认的 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,因此完全可以在信号处理程序中使用。