使用 sigaction 接收到信号时重新启动进程
Restarting process when receiving a signal with sigaction
我正在尝试让我的进程在接收到 SIGUSR1
时重新启动。
因为 SIGINT
更容易测试,所以我用它来代替。
代码如下:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void sig_handler(int signo){
if (signo == SIGINT){
char *args[] = { "./a", NULL };
write(1, "Restarting...\n", 14);
execv(args[0], args);
}
}
int main(void) {
printf("Starting...\n");
struct sigaction saStruct;
sigemptyset(&saStruct.sa_mask);
sigaddset(&saStruct.sa_mask, SIGINT);
saStruct.sa_flags = SA_NODEFER;
saStruct.sa_handler = sig_handler;
sigaction(SIGINT, &saStruct, NULL);
while (1)
sleep(1);
}
不幸的是,这仅在第一次收到信号时有效。之后,它什么都不做。我认为 SA_NODEFER
标志应该使它按照我想要的方式工作,但事实并非如此。
此外,当我尝试使用 SIGUSR1
时,它只是终止了进程。
问题出在这里:
sigaddset(&saStruct.sa_mask, SIGINT);
NODEFER 影响信号的方式是:
If NODEFER is set, other signals in sa_mask are still blocked.
If NODEFER is set and the signal is in sa_mask, then the signal is
still blocked.
另一方面(来自Signals don't re-enable properly across execv()):
When using signal() to register a signal handler, that signal number
is blocked until the signal handler returns - in effect the kernel /
libc blocks that signal number when the signal handler is invoked, and
unblocks it after the signal handler returns. As you never return from
the signal handler (instead you execl a new binary), SIGUSR1 stays
blocked and so isn't caught the 2nd time.
只需删除以下行:
sigaddset(&saStruct.sa_mask, SIGINT);
大功告成。
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sighandler(int signo)
{
if (signo == SIGUSR1)
{
char *args[] = {"./demo", NULL};
char str[] = "Restarting...\n";
write(1, str, sizeof(str) - 1);
execv(args[0], args);
}
}
int main(void)
{
printf("Starting...\n");
struct sigaction act;
act.sa_handler = sighandler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
while (1)
{
sleep(1);
}
}
我正在尝试让我的进程在接收到 SIGUSR1
时重新启动。
因为 SIGINT
更容易测试,所以我用它来代替。
代码如下:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void sig_handler(int signo){
if (signo == SIGINT){
char *args[] = { "./a", NULL };
write(1, "Restarting...\n", 14);
execv(args[0], args);
}
}
int main(void) {
printf("Starting...\n");
struct sigaction saStruct;
sigemptyset(&saStruct.sa_mask);
sigaddset(&saStruct.sa_mask, SIGINT);
saStruct.sa_flags = SA_NODEFER;
saStruct.sa_handler = sig_handler;
sigaction(SIGINT, &saStruct, NULL);
while (1)
sleep(1);
}
不幸的是,这仅在第一次收到信号时有效。之后,它什么都不做。我认为 SA_NODEFER
标志应该使它按照我想要的方式工作,但事实并非如此。
此外,当我尝试使用 SIGUSR1
时,它只是终止了进程。
问题出在这里:
sigaddset(&saStruct.sa_mask, SIGINT);
NODEFER 影响信号的方式是:
If NODEFER is set, other signals in sa_mask are still blocked.
If NODEFER is set and the signal is in sa_mask, then the signal is still blocked.
另一方面(来自Signals don't re-enable properly across execv()):
When using signal() to register a signal handler, that signal number is blocked until the signal handler returns - in effect the kernel / libc blocks that signal number when the signal handler is invoked, and unblocks it after the signal handler returns. As you never return from the signal handler (instead you execl a new binary), SIGUSR1 stays blocked and so isn't caught the 2nd time.
只需删除以下行:
sigaddset(&saStruct.sa_mask, SIGINT);
大功告成。
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sighandler(int signo)
{
if (signo == SIGUSR1)
{
char *args[] = {"./demo", NULL};
char str[] = "Restarting...\n";
write(1, str, sizeof(str) - 1);
execv(args[0], args);
}
}
int main(void)
{
printf("Starting...\n");
struct sigaction act;
act.sa_handler = sighandler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_NODEFER;
sigaction(SIGUSR1, &act, 0);
while (1)
{
sleep(1);
}
}