From man -e 2 wait:
The call wait(&status) is equivalent to: waitpid(-1, &status, 0);
errno values:
EINTR WNOHANG was not set and an unblocked signal or a SIGCHLD was caught; see signal(7).
So I from my understanding of above, if we are blocked in 'wait' and receiving a signal (SIGCHLD), the call should return with -1 and errno set to EINTR. Though running the following snippet will prove that wait is actually restarted (linux 4.15.0-43, glibc 2.23):
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
static void sigchld_handler(int signo)
{
const char *const msg = "\nSIGCHLD";
(void)signo;
write(STDERR_FILENO, msg, strlen(msg));
}
int main(void)
{
pid_t wait_ret = 0, pid = 0;
int status = 0, ret = -1;
sigaction(SIGCHLD, &(struct sigaction){
.sa_handler = sigchld_handler,
}, NULL);
if ((pid = fork()) < 0)
{
perror("\nfork: ");
goto Exit;
}
if (!pid)
{
sleep(3);
return 0;
}
if ((wait_ret = wait(&status)) < 0)
{
perror("\nwait: ");
goto Exit;
}
fprintf(stderr, "\nwait done, pid %d", wait_ret);
ret = 0;
Exit:
fprintf(stderr, "\n");
return ret;
}
SA_RESTART is not set - so why does 'wait' restart.? Actual output:
SIGCHLD wait done, pid 15242
Expected by me output:
SIGCHLD wait: Interrupted system call
Note kill -CHLD <waiting process> manually from shell will give the expected result.
Also note that running the code on FreeBSD 11.2 will give the expected result as well - wait is interrupted with error on child exit.
waitpidwould not otherwise return (i.e. some child other than the one waited for exited). - Erki Aring