简体   繁体   English

如何为SIGCHLD制作信号处理程序,以便在shell中获得后台进程?

[英]How to make a signal handler for SIGCHLD that will reap background processes in shell?

Currently I'm making a shell and it works fine for the foreground processes that it executes. 目前我正在制作一个shell,它适用于它执行的前台进程。 Now I have to implement background processes and job control and I am honestly confused on how I should approach it. 现在我必须实现后台进程和作业控制,我真的很困惑我应该如何处理它。 I understand that if I want to run the proccesses in the background, I should set their pgid and simply not wait for them, however I have hit a wall when trying to reap them... 我明白,如果我想在后台运行proccesses,我应该设置他们的pgid而不是等待它们,但是当我试图收获它们时我碰到了墙...

I have two structs: job and process 我有两个结构:工作和流程

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;

The important part is that a job consists of a linked list of process structs and that there is a global list of job structs which represents all of my background jobs going on. 重要的一点是,作业由一个过程结构的链接列表组成,并且有一个全局的作业结构列表,代表我正在进行的所有后台作业。

The shell algorithm is kind of standard. shell算法是一种标准。

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

Now here's my issue. 现在这是我的问题。 If I have a bunch of processes that are being executed in the background, that means any one of them (from any one of the background jobs) could simply end and then send SIGCHLD. 如果我有一堆正在后台执行的进程,这意味着它们中的任何一个(来自任何一个后台作业)都可以简单地结束然后发送SIGCHLD。 The annoying part is that if all processes for a certain job end, I have to remove that job from the global jobs list. 令人讨厌的部分是,如果某个作业的所有进程都结束,我必须从全局作业列表中删除该作业。 I don't think I can call a loop of waitpid(-1, &status, WNOHANG) in my SIGCHLD handler here because on the off chance that the forground process currently executing finsihes while in the signal handler. 我不认为我可以在我的SIGCHLD处理程序中调用waitpid(-1,&status,WNOHANG)的循环,因为在信号处理程序中,forground进程当前正在执行finsihes的可能性很小。

Does this mean I have to go through and waitpid() on every process of every job as soon as a get a SIGCHLD so that I only wait on non-fg processes? 这是否意味着我必须在获得SIGCHLD后立即对每个作业的每个进程进行waitpid()以便我只等待非fg进程?

I don't really need code, just an explanation on a good way to do this. 我真的不需要代码,只是解释一个很好的方法来做到这一点。

I know this is really late and probably irrelevent to you now, but I'm working on a shell as well and ran into your question while trying to figure out this same problem. 我知道现在这已经很晚了,可能对你来说无关紧要,但我也正在研究一个shell,并试图找出同样的问题时遇到了你的问题。

Anyways, it seems like the problem here is getting the main process to wait for all of the foreground children, but this is difficult do to the call to waitpid in the SIGCHLD handler. 无论如何,似乎这里的问题是让主进程等待所有前台子进程,但是这很难对SIGCHLD处理程序中的waitpid进行调用。 How I did this was instead of using a wait() call in the main process, I just reaped all processes in the handler and removed them from the appropriate list (I currently have a list for all foreground processes and list for all background processes), and then in the main process I did: 我是如何做到这一点的,而不是在主进程中使用wait()调用,我只是在处理程序中获取所有进程并从适当的列表中删除它们(我目前有一个所有前台进程的列表和所有后台进程的列表) ,然后在主要过程中我做了:

while(foreground process list is not empty)
    pause();

The pause() call just puts the process to sleep until it is woken up by a signal, and in this case SIGCHLD will always awaken the process so that is can again check if there are any foreground processes still running that is needs to wait for. pause()调用只是将进程置于睡眠状态,直到被信号唤醒为止,在这种情况下, SIGCHLD将始终唤醒进程,以便再次检查是否还有正在运行的前台进程需要等待。 Hope this helps someone! 希望这有助于某人!

Edit: Just realized this could cause a race condition if the child terminates right after you check that the list is not empty, and before you call pause() . 编辑:刚刚意识到这可能会导致竞争条件,如果孩子在您检查列表不为空之后立即终止,并且在您调用pause() Simple way around this is to just use nanosleep instead of pause, it will still be interrupted by a signal but gives you the option to check the list size periodically, which avoids the race condition in this case 简单的方法是只使用nanosleep而不是暂停,它仍然会被信号中断,但是你可以选择定期检查列表大小,这样可以避免在这种情况下的竞争条件

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM