如何为SIGCHLD制作一个信号处理程序,以便在shell中获得后台进程?
目前我正在制作一个shell,它对它所执行的前台进程工作正常。现在我必须实施后台流程和工作控制,并且我对我应该如何处理它感到困惑。我明白,如果我想在后台运行proccesses,我应该设置他们的pgid,而不是等待他们,但是我试图收获他们时碰壁了...如何为SIGCHLD制作一个信号处理程序,以便在shell中获得后台进程?
我有两个结构:job和处理
typedef struct job {
int is_background_job;
pid_t pgid;
int job_status;
process *p; // List of processes to execute for this job
struct job *next; // If a background job, it will be in a global linked list of job structs
} job;
typedef struct process {
char **argv;
process *next; // The next process to pipe to
} process;
的重要组成部分,是一个作业由工艺结构的链接列表,并有代表我所有的后台作业的事情工作结构的全局列表。
shell算法是一种标准。
壳:
get cmd from terminal
parse cmd and create a job struct filled with processes
if job is a background job:
add it to global background job list
fork(), setpgid, and do the piping in a while loop of the job's processes
if job is a foreground process:
wait on the forked processes
else:
don't wait // since it's a background process
continue to loop and read next cmd from terminal
现在,这里是我的问题。如果我有一堆正在后台执行的进程,这意味着它们中的任何一个(来自任何一个后台作业)都可以简单地结束并发送SIGCHLD。烦人的部分是,如果某个作业的所有进程都结束了,我必须从全局作业列表中删除该作业。我不认为我可以在我的SIGCHLD处理程序中调用waitpid循环(-1,&状态,WNOHANG),因为在信号处理程序中,forground进程当前正在执行finsihes。
这是否意味着我必须在每一个工作的每一个进程中通过waitpid(),只要获得一个SIGCHLD,以便我只等待非fg进程?
我真的不需要代码,只是解释一个很好的方法来做到这一点。
我知道这对你来说真的很晚,可能无法解决,但我正在研究一个shell,并在试图找出同样的问题时遇到了你的问题。
无论如何,这似乎是问题在于让主流程等待所有前台儿童,但这对处理中的waitpid
呼叫很困难。我是如何做到的,而不是在主进程中使用wait()
调用,我刚收获处理程序中的所有进程,并将它们从适当的列表中删除(我目前有一个所有前台进程的列表和所有后台进程的列表),以及然后在主过程中,我做的事:
while(foreground process list is not empty)
pause();
的pause()
调用只是把该进程进入睡眠状态,直到被信号唤醒,在这种情况下SIGCHLD
总会唤醒过程,这样是可以再次检查有任何需要等待的前台进程仍在运行。希望这可以帮助别人!
编辑:刚才意识到这可能会导致竞争条件,如果孩子在您检查列表不是空的之前终止,并且在您致电pause()
之前。简单的解决方法是仅使用nanosleep
而不是暂停,它仍然会被信号打断,但是可以让您选择定期检查列表大小,这样可以避免竞争情况在这种情况下
谢谢,我刚刚完成作业时有点晚。自从你付出了额外的努力之后,我会标记这一点。 – ParadoxicalEnigma
“因为关闭机会在信号处理程序中当前正在执行finsihes的forground进程“。那么如果前台进程结束了呢?处理它。它不会在后台列表中,因此您知道这不是后台进程。 – kaylum
尽管如果一个进程在信号处理程序中终止,您可以使用'sigaction'来屏蔽它们,在isr之后您可以处理其他进程的信号处理程序 – Anjaneyulu
对不起,延迟响应。但kaylum,如果在fork的父节点开始等待之前forground进程在sighandler中完成,那么会导致waitpid在fork之后永久挂起的forground进程? – ParadoxicalEnigma