【发布时间】:2012-12-11 16:12:52
【问题描述】:
我正在编写一个 mini-shell(不,不是为了学校 :P;为了我自己的乐趣)并且大部分基本功能现在已经完成,但是在尝试处理 SIGTSTP 时我被卡住了。
假设当用户按下Ctrl+Z时,如果存在SIGTSTP应该发送到shell的Foreground进程,并且Shell应该正常继续。
创建每个进程后(如果是前台进程),下面的代码等待:
if(waitpid(pid, &processReturnStatus, WUNTRACED)>0){//wait stopped too
if(WIFEXITED(processReturnStatus) || WIFSIGNALED(processReturnStatus))
removeFromJobList(pid);
}
我正在按如下方式处理信号:
void sigtstpHandler(int signum)
{
signum++;//Just to remove gcc's warning
pid_t pid = findForegroundProcessID();
if(pid > -1){
kill(-pid, SIGTSTP);//Sending to the whole group
}
}
发生的情况是,当我按下Ctrl+Z 时,子进程确实被挂起(使用ps -all 查看进程的状态)但我的shell 挂在waitpid,即使我通过了@,它也永远不会返回987654327@ 标志,据我了解,它也应该在进程停止时使waitpid 返回。
那么我可能做错了什么?还是我错误地理解了waitpid的行为?
注意事项:
-findForegroundProcessID() 返回正确的 pid;我仔细检查了。
-我在fork 之后立即更改每个进程的组
-处理Ctrl+C 工作得很好
- 如果我在我的 shell 挂起后使用另一个终端发送 SIGCONT,子进程将恢复其工作,并且 shell 最终会获得它。
-我正在捕获 SIGTSTP,据我阅读(和测试)可以捕获它。
- 我尝试使用 waitid 而不是 waitpid 以防万一,问题仍然存在。
编辑:
void sigchldHandler(int signum)
{
signum++;//Just to remove the warning
pid_t pid;
while((pid = waitpid(-1, &processReturnStatus, 0)) > 0){
removeFromJobList(pid);
}
if(errno != ECHILD)
unixError("kill error");
}
我的 SIGCHLD 处理程序。
【问题讨论】:
-
IIUC,您正在尝试捕获 SIGSTP。您无法捕获 SIGSTP 或 SIGKILL。
-
我不确定 SIGSTOP 是否与 SIGSTP 相同,但根据一本书,SIGSTOP 无法被捕获,但 SIGTSTP 可以,事实上我确信我抓住了它,因为我确实打印了一些东西作为测试
-
糟糕,我的错。如果我没看错的话,SIGTSTP 是故意创建的,以允许它被捕获,以允许进程组/终端组在其成员之间传播它。如果你所指的书是APUE,那你应该可以正确地做……
-
您的 waitpid() 调用看起来不错,因此请测试您的其他假设。当在 waitpid() 中被阻止时,如果你从另一个终端“杀死 -TSTP”孩子会发生什么?如果你从另一个终端“杀死 -KILL”孩子会发生什么?
-
@fizzer 'kill -TSTP' 挂起 shell,再次发送 kill -CONT 让它继续正常工作(如,孩子恢复并且 shell 继续等待)。发送 kill -KILL 终止子进程,等待返回,shell 正常继续
标签: c linux shell signals wait