SIGTSTP不会被子进程捕获

时间:2019-12-18 19:19:04

标签: c shell signals jobs keyboardinterrupt

我正在用C编写一个shell项目,更具体地说是在它的作业控制方面。我正在测试后期,这就是我正在发生的事情:

我正在创建要停止的前台作业,这要归功于ctrl-Z(或用Ctrl-C中断;我得到的行为完全相同),并且我正在诸如“ ls -R / “。

我第一次暂停作业的效果很好:我得到了输入,我在作业列表中看到了暂停的作业,等等。

然后,我尝试启动第二个“ ls -R /”(第一个仍然停止),但是这次我无法停止它;而且我似乎不知道为什么...

该作业位于终端的前台(通过“ ps -o state”命令检查),如果我在父外壳中硬编码kill(SIGTSTP),它将捕获SIGTSTP信号(但不会捕获)从另一个shell发送的“ kill -TSTP [pid_of_child]”命令),我可以看到Ctrl-Z(我在终端上键入内容),但是它不会停止。似乎第一个ls调用切换了一些阻止信号处理程序的东西。

似乎也可能在随机调用“ ls -R /”之后发生这种现象(虽然通常是第二个,但它并非总是不可阻挡的)。

出于明显的原因,我没有在此处发布42sh的所有代码。有点困难:

void                    ft_set_child_signal(int shell_pid)
{

sigset_t                wakeup_sig;
struct sigaction        action;

ft_bzero(&action, sizeof(sigaction));
action.sa_handler = &ft_catch_sigusr1;
sigaction(SIGUSR1, &action, NULL);

sigfillset(&wakeup_sig); // is here for synchronicity of multi-process jobs.
sigdelset(&wakeup_sig, SIGUSR1); //same
kill(shell_pid, SIGUSR1); //same
sigsuspend(&wakeup_sig); //same
signal(SIGCONT, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTSTP, SIG_DFL); // is reset to default in child while SIG_IGN in parent
signal(SIGTTIN, SIG_DFL);
signal(SIGTTOU, SIG_DFL);
signal(SIGUSR1, SIG_IGN);
signal(SIGUSR2, SIG_IGN);
}

当然,在该ft_set_child_signal函数之后,我将调用execve(这可能会重置信号的行为?或者我读了)。我确保所有子进程都是直接从shell派生的。这是我在父母中等待孩子的方式:

int             ft_wait_foreground(t_job* job)
{
sigset_t        wakeup_sig;

tcsetpgrp(STDIN_FILENO, job->pgid);
sigfillset(&wakeup_sig);
sigdelset(&wakeup_sig, SIGCHLD);
killpg(job->pgid, SIGUSR1);
ft_dprintf(2, "Job in foreground: %i\n", tcgetpgrp(0));
while (ISRUNNING(job->status))
        sigsuspend(&wakeup_sig);
tcsetpgrp(STDIN_FILENO, getpid());
if (WIFSTOPPED(job->status))
        return (job->status);
return (((t_process*)(job->process->content))->status);
}

void            ft_sigchld_handler(int nbr)
{
int                     ret_status;
int                     pid;
t_job           *job;
t_process       *process;

(void)nbr;
while ((pid = waitpid(-1, &ret_status, WUNTRACED | WNOHANG)) > 0)
{
ft_dprintf(2, "handler: wait caught pid: %i\n", pid);
        if ((job = ft_get_job_pgid(pid)))
        {
                job->status = ret_status | (BACKGROUND &job->status);
                process = ft_get_process_from_job(job, pid);
        }
        else if (!(process = ft_get_process_pid(pid)))
                continue ;
        ft_dprintf(2, "handler: process updated: %i\n", ret_status);
        process->status = ret_status;
}
ft_update_job_status();
}

如果您发现任何错误或对我的问题有任何想法,请告诉我(我也在接受任何建议:)

0 个答案:

没有答案