考虑以下 POSIX 系统的 C 代码:
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#define CONTINUE_SIGNAL SIGINT
void continue_handler(int sig, siginfo_t *info, void *context)
{
printf("[P] Continuing process with pid = %d...\n", getpid());
}
int main(void)
{
struct sigaction act;
sigset_t mask;
pid_t pid;
// Block the CONTINUE_SIGNAL for now.
sigemptyset(&mask);
sigaddset(&mask, CONTINUE_SIGNAL);
sigprocmask(SIG_BLOCK, &mask, NULL);
if ((pid = fork()) == 0) {
printf("[C] This is the child (pid %d).\n", getpid());
return 0;
}
printf("[P] Parent (pid %d) has spawned child (pid %d).\n", getpid(), pid);
// Call the 'continue_handler' when CONTINUE_SIGNAL is received.
act.sa_sigaction = continue_handler;
act.sa_flags = SA_SIGINFO;
sigaction(CONTINUE_SIGNAL, &act, NULL);
printf("[P] Waiting for CONTINUE_SIGNAL...\n");
// Block all signals except CONTINUE_SIGNAL and wait for it to occur.
sigfillset(&mask);
sigdelset(&mask, CONTINUE_SIGNAL);
sigsuspend(&mask);
printf("[P] Signal received. Exiting...\n");
return 0;
}
请注意,我已删除所有错误检查,以便能够以更紧凑的形式表示它。但是,我已经验证了在以下两种情况下所有函数都成功返回。
在 Linux 系统上,代码完全符合我的预期:父进程生成一个子进程并等待 SIGINT
,然后继续执行 continue_handler
.
[P] Parent (pid 804) has spawned child (pid 805).
[P] Waiting for CONTINUE_SIGNAL...
[C] This is the child (pid 805).
<press Ctrl+C>
[P] Continuing process with pid = 804...
[P] Signal received. Exiting...
然而,在 macOS 上,我获得了以下输出(没有任何交互):
[P] Parent (pid 6024) has spawned child (pid 6025).
[P] Waiting for CONTINUE_SIGNAL...
[C] This is the child (pid 6025).
[P] Signal received. Exiting...
很明显,父进程(pid 6024)的sigsuspend
调用在子进程退出后立即返回。虽然SIGINT
似乎没有被触发,但是sigsuspend
返回一个EINTR
的errno
,即报告成功终止通过非屏蔽信号之一。请注意,如果我阻止子进程退出,sigsuspend
不会自行返回,而是等待 SIGINT
被传送。
我使用 API 的方式有问题吗?还是 POSIX 规范中可能存在某种程度的灵 active ,使得这两种行为都符合预期?
最佳答案
关于c - 为什么退出的子进程会导致父进程的 sigsuspend 调用在 macOS 上返回?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62252854/