目前我正在制作一个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进程?
我真的不需要代码,只是解释一个很好的方法来做到这一点。
“因为关闭机会在信号处理程序中当前正在执行finsihes的forground进程“。那么如果前台进程结束了呢?处理它。它不会在后台列表中,因此您知道这不是后台进程。 – kaylum
尽管如果一个进程在信号处理程序中终止,您可以使用'sigaction'来屏蔽它们,在isr之后您可以处理其他进程的信号处理程序 – Anjaneyulu
对不起,延迟响应。但kaylum,如果在fork的父节点开始等待之前forground进程在sighandler中完成,那么会导致waitpid在fork之后永久挂起的forground进程? – ParadoxicalEnigma