我正在用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();
}
如果您发现任何错误或对我的问题有任何想法,请告诉我(我也在接受任何建议:)