Consider the following C code for a POSIX system:
#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;
}
Note that I have removed all error checking to be able to represent it in a more compact form. However, I have verified that all the functions return successfully in both of the following cases.
On a Linux system, the code does exactly what I expect it to do: The parent process spawns a child process and waits for SIGINT
before it continues to execute 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...
On macOS, however, I obtain the following output (without any interaction):
[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...
Obviously, the sigsuspend
call of the parent process (pid 6024) returns immediately after the child process exits. Although SIGINT
does not seem to be triggered, sigsuspend
returns an errno
of EINTR
, i.e., reports a successful termination by one of the non-masked signals. Note that if I prevent the child process from exiting, sigsuspend
does not return by itself and instead waits for SIGINT
to be delivered.
Is there an issue with the way I am using the API? Or is there maybe a certain degree of flexibility in the POSIX specification that makes both of these behaviors expected?