我正在为一个系统课程的shell实验室工作,我一直有一些非常奇怪的竞争条件错误,我一直试图解决,因为星期五晚上,似乎无法确定。
我目前的代码:http://buu700.com/tsh
课程讲师提供START OF MY CODE
之前和END OF MY CODE
之后的所有内容,因此这些都不应成为问题的根源。
我们也有一个测试脚本;这是我当前测试结果的输出:http://buu700.com/sdriver
/*****************
* Signal handlers
*****************/
/*
* sigchld_handler - The kernel sends a SIGCHLD to the shell whenever
* a child job terminates (becomes a zombie), or stops because it
* received a SIGSTOP, SIGTSTP, SIGTTIN or SIGTTOU signal. The
* handler reaps all available zombie children, but doesn't wait
* for any other currently running children to terminate.
*/
void
sigchld_handler(int sig)
{
pid_t pid;
int status, termsig;
struct job_t *job;
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGCHLD);
sigaddset(&s, SIGINT);
sigaddset(&s, SIGTSTP);
sigprocmask(SIG_BLOCK, &s, NULL);
while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
if (WIFEXITED(status)) {
deletejob(job_list, pid);
}
if ((termsig = WTERMSIG(status))) {
deletejob(job_list, pid);
safe_printf("Job [%i] (%i) %s by signal %i\n",
pid2jid(pid), pid, "terminated", termsig);
}
if (WIFSTOPPED(status)) {
job = getjobpid(job_list, pid);
job->state = ST;
safe_printf("Job [%i] (%i) %s by signal %i\n",
pid2jid(pid), pid, "stopped", SIGTSTP);
}
}
if (errno != ECHILD)
unix_error("waitpid error");
sigprocmask(SIG_UNBLOCK, &s, NULL);
return;
}
/*
* sigint_handler - The kernel sends a SIGINT to the shell whenver the
* user types ctrl-c at the keyboard. Catch it and send it along
* to the foreground job.
*/
void
sigint_handler(int sig)
{
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGCHLD);
sigaddset(&s, SIGINT);
sigaddset(&s, SIGTSTP);
sigprocmask(SIG_BLOCK, &s, NULL);
kill(-1, sig);
sigprocmask(SIG_UNBLOCK, &s, NULL);
return;
}
/*
* sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever
* the user types ctrl-z at the keyboard. Catch it and suspend the
* foreground job by sending it a SIGTSTP.
*/
void
sigtstp_handler(int sig)
{
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGCHLD);
sigaddset(&s, SIGINT);
sigaddset(&s, SIGTSTP);
sigprocmask(SIG_BLOCK, &s, NULL);
kill(-1, sig);
sigprocmask(SIG_UNBLOCK, &s, NULL);
return;
}
答案 0 :(得分:1)
我怀疑这个错误来自你与信号处理程序中其他信号的竞争:
sigint_handler(int sig)
{
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGCHLD);
sigaddset(&s, SIGINT);
sigaddset(&s, SIGTSTP);
sigprocmask(SIG_BLOCK, &s, NULL);
当您使用sigaction(2)
注册信号处理程序时,您可以提供一个sa_mask
,在您的信号处理程序运行时,内核将使用该SIGTSTP
来阻止信号。这是以原子方式完成的,不需要您做额外的工作。注册信号处理程序时,只需填充一次这个掩码。
另一种可能性来自SIGTSTP
信号;我的APUE, 2nd edition副本的第350页在部分内容中说:
只有作业控制外壳应将[
SIGTTIN
,SIGTTOU
,SIG_DFL
]的处置方式重置为SIG_DFL
。
在这些段落中没有说明什么,但我认为可以公平地说,shell应该为子进程设置信号处理{{1}} - 它仍然需要做一些事情来处理信号本身。
您是否正确处理了孩子们的信号处理?