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
SIGINTto the entire foreground process group: parents and children.waitpid(2)returning-1, and settingerrnotoEINTR, 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_RESTARTflag in the.sa_flagsmember of thestruct sigactionstructure provided tosigaction(2)to havewaitpidautomatically 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 causewaitpidin the parent process to return-1(there are OS-specific behaviours, like the handling ofSIGCHILDon Linux).