waitpid() returns -1 from time to time when the process in question has received a SIGINT via a ^C. But I can't reproduce this problem if I send a SIGINT signal via pkill
for example.
The value of errno is set to EINTR.
I have a parent process that creates sub processes to execute commands received from the STDIN with execve().
sigaction handler for SIGINT and SIGQUIT is set to SIG_DFL for the child only. sigaction handler for SIGINT is set to sighandler() (see below) and SIGQUIT is set to SIG_IGN for the parent only.
void sighandler(int signum)
{
(void) signum;
g_signal = true;
rl_done = 1;
}
After launching all the forks from the parent. I make a call to waitpid() on all the pid that have been created, and with wstatus I can get back the output value of the commands, and also allows me to know if the process has been terminated by a signal.
void pid_lst_wait(t_pid_lst **pid_lst, int *wstatus)
{
t_pid_lst *ptr_pid_lst;
*wstatus = 0;
if (*pid_lst == NULL)
return ;
ptr_pid_lst = *pid_lst;
while (ptr_pid_lst)
{
if (waitpid(ptr_pid_lst->pid, wstatus, 0) == -1)
ft_dprintf(STDERR_FILENO, "waitpid: Failed to wait %d\n", ptr_pid_lst->pid);
ptr_pid_lst = ptr_pid_lst->next;
}
pid_lst_clear(*pid_lst);
*pid_lst = NULL;
}
Since waitpid fail I can't set a return status to indicate a SIGINT was sent.
EDIT: As nos say here I need to use SA_RESTART to avoid this behavior.
typedef struct sigaction t_sigaction;
uint8_t signal_init(void)
{
t_sigaction sa;
sa = (t_sigaction){0};
sigemptyset(sa.sa_mask);
sa.sa_handler = SIG_IGN;
if (sigaction(SIGQUIT, &sa, NULL) == -1)
return (SSYSCALL_ERROR);
sa.sa_handler = sighandler;
sa.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sa, NULL) == -1)
return (SSYSCALL_ERROR);
return (SSUCCESS);
}
In your common shell (e.g., Bash), ^C sends SIGINT
to the entire foreground process group: parents and children.
waitpid(2)
returning -1
, and setting errno
to EINTR
, is the expected default behaviour when the function is interrupted by the delivery of an unblocked signal in the calling process (i.e., in the parent).
You can specify the SA_RESTART
flag in the .sa_flags
member of the struct sigaction
structure provided to sigaction(2)
to have waitpid
automatically restart after the delivery of the signal is handled (see also: signal(7)
).
Generally speaking, the delivery of a signal to a child process (say via pkill
) will not cause waitpid
in the parent process to return -1
(there are OS-specific behaviours, like the handling of SIGCHILD
on Linux).