/* * do_bgfg - Execute the builtin bg and fg commands */ voiddo_bgfg(char **argv)// finished { if (argv[1] == NULL || argv[2] != NULL) { printf("%s command requires PID or %%jobid argument\n", argv[0]); return; } int id; structjob_t *job =NULL; if (sscanf(argv[1], "%%%d", &id)) // JID { job = getjobjid(jobs, id); if (!job) { printf("%%%d: no such job\n", id); return; } } elseif (sscanf(argv[1], "%d", &id)) // PID { job = getjobpid(jobs, id); if (!job) { printf("(%d): no such process\n", id); return; } } else// 输入有误!!! { printf("%s: argument must be a PID or %%jobid\n", argv[0]); return; } if (strcmp(argv[0], "bg")) // fg--在前台运行//strcmp--匹配则返回0 { kill(-(job->pid), SIGCONT); job->state = FG; waitfg(job->pid); // 等待 } else// bg-在后台运行 { kill(-(job->pid), SIGCONT); job->state = FG; printf("[%d](%d)+ %s", job->jid, job->pid, job->cmdline); // 打印相关信息 } return; }
waitfg
这个函数需要我们使用sigsuspend等待前台运行程序结束,没啥好讲的
代码
1 2 3 4 5 6 7 8 9 10 11 12 13
/* * waitfg - Block until process pid is no longer the foreground process */ voidwaitfg(pid_t pid)// doing { sigset_t child; sigemptyset(&child); // 似乎不用阻塞任何信号? while (fgpid(jobs)) // 当jobs中没有前台函数时,fgpid返回0 { sigsuspend(&child); } return; }
sigchld_handler
在这个程序中,sigchld_handler是进程收到了SIGCHLD函数以后的信号处理程序
WriteUp中有一句Hint:The WUNTRACED and WNOHANG options to waitpid will also be useful,查阅CSAPP,发现WNOHANG|WUNTRACED是指立即返回,如果等待集合中的子进程没有终止,就返回0,如果有一个停止或终止就返回该进程的pid
/* * 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 or SIGTSTP signal. The handler reaps all * available zombie children, but doesn't wait for any other * currently running children to terminate. */ voidsigchld_handler(int sig)// finished,OK? { int olderrno = errno; // 保存和恢复errno pid_t pid; sigset_t block, prev; int status; sigfillset(&block); while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { if (WIFSTOPPED(status)) // 暂停,打印信息,设置状态 { structjob_t *job = getjobpid(jobs, pid); sigprocmask(SIG_BLOCK, &block, &prev); printf("[%d](%d)+ %s stopped", job->jid, job->pid, job->cmdline); job->state = ST; sigprocmask(SIG_SETMASK, &prev, NULL); } else// 正常退出,删除作业 { sigprocmask(SIG_BLOCK, &block, &prev); deletejob(jobs, pid); // printf("\n\nABCDEFG%d\n\n", pid); sigprocmask(SIG_SETMASK, &prev, NULL); } } errno = olderrno; 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. */ voidsigtstp_handler(int sig) { int olderrno = errno; pid_t pid = fgpid(jobs); if (pid != 0) kill(-pid, sig); errno = olderrno; return; }