waitpid()在相关进程通过^C接收到SIGINT信号时会不时返回-1。但是,如果我通过pkill
发送SIGINT信号,就无法重现这个问题。
errno的值设置为EINTR。
我有一个父进程,它创建子进程来执行从STDIN(使用execve())接收到的命令。
SIGINT和SIGQUIT的sigaction处理程序设置为SIG_DFL(仅用于子级)。SIGINT的sigaction处理程序设置为sighandler()(见下文),SIGQUIT设置为SIG_IGN(仅用于父级)。
void sighandler(int signum)
{
(void) signum;
g_signal = true;
rl_done = 1;
}
在从父进程启动所有fork之后,我对所有已经创建的pid调用waitpid(),使用wstatus我可以取回命令的输出值,并且还允许我知道进程是否已经被一个信号终止。
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;
}
由于waitpid失败,我无法设置返回状态以指示SIGINT已发送。
编辑:正如nos所说的here,我需要使用SA_RESTART来避免这种行为。
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);
}
2条答案
按热度按时间voj3qocg1#
在公共shell(例如Bash)中,^C将
SIGINT
发送到整个前台进程组:父母和孩子。返回
-1
并将errno
设置为EINTR
是当函数被调用过程(即,在父进程中)中的未阻塞信号的传递中断时的预期默认行为。您可以在提供给
sigaction(2)
的struct sigaction
结构的.sa_flags
成员中指定SA_RESTART
标志,以使waitpid
在处理完信号传递后自动重新启动(另请参见:signal(7)
)。一般来说,将信号传递给一个 * 子 * 进程(比如通过
pkill
)不会导致 * 父 * 进程中的waitpid
返回-1
(存在特定于操作系统的行为,比如在Linux上处理SIGCHILD
)。bakd9h0s2#
当您使用任何exec系统调用执行命令时,该命令创建的进程将接管调用exec系统调用的进程。因此,您在exec调用后尝试使用或访问的任何变量或代码都将无法工作。例如:
末尾的printf语句将不会被调用,因为由exec调用创建的进程完全接管了子进程。
因此,一旦执行exec系统调用,您在子进程中创建的信号处理程序就会丢失,而由exec调用创建的进程可能会创建自己的信号处理程序。
如果不了解进程和信号处理程序是如何/在何处创建的,我想我无法提供更多帮助,但如果您希望在父进程接收SIGINT时终止子进程,则必须在主进程中设置一个信号处理程序来处理SIGINT,然后在接收到SIGINT时,您可以在该信号处理程序中终止子进程。例如: