shell lab

实现几个函数,使得该shell能处理前后台运行程序、能够处理ctrl+z、ctrl+c等信号。
实现这几个函数:
eval: Main routine that parses and interprets the command line. [70 lines] builtin cmd: Recognizes and interprets the built-in commands: quit, fg, bg, and jobs. [25 lines] do bgfg: Implements the bg and fg built-in commands. [50 lines] waitfg: Waits for a foreground job to complete. [20 lines] sigchld handler: Catches SIGCHILD signals. 80 lines] sigint handler: Catches SIGINT (ctrl-c) signals. [15 lines] sigtstp handler: Catches SIGTSTP (ctrl-z) signals. [15 lines]

  

eval: 主要功能是解析cmdline,并且运行. [70 lines]
builtin_cmd: 辨识和解析出bulidin命令: quit, fg, bg, and jobs. [25lines]
do_bgfg: 实现bg和fg命令. [50 lines] 
waitfg: 实现等待前台程序运行结束. [20 lines]
sigchld_handler: 响应SIGCHLD. 80 lines]
sigint_handler: 响应 SIGINT (ctrl-c) 信号. [15 lines] 
sigtstp_handler: 响应 SIGTSTP (ctrl-z) 信号. [15 lines]

注意:

阅读课本第8章(异常控制流程)。

使用跟踪文件来指导shell的开发。从trace01开始,确保shell生成与参考shell相同的输出。

然后转到文件trace02.txt,这样继续往下。

waitpid、kill、fork、execve、setpgid和sigprocmask函数将非常有用。

wuntracking和WNOHANG选项对于waitpid也很有用。

在实现信号处理程序时,确保将SIGINT和SIGTSTP信号发送到整个前台进程组,在kill函数的参数中使用“-pid”而不是“pid”。

sdriver.pl程序测试这个错误。

任务中比较棘手的部分之一是决定waitfg之间的工作分配和sigchld处理函数。建议采用以下方法:

  -在waitfg中,使用sleep函数的一个繁忙循环。

  -在sigchld处理程序中,只使用一个对waitpid的调用。

虽然可以使用其他解决方案,例如在waitfg和sigchld处理程序中调用waitpid。

在eval中,父进程必须先使用sigprocmask来阻止SIGCHLD信号,然后再派生子进程,

然后解压这些信号,再次使用sigprocmask,在它将子节点添加到作业列表by之后

调用addjob。由于孩子继承了他们父母的阻塞向量,孩子必须在SIGCHLD执行新程序之前解除它的信号阻塞。父进程需要以这种方式阻塞SIGCHLD信号,以避免其中的竞态条件

sigchld_handler在父进程调用addjob之前捕获子进程(因此从作业列表中删除)。

诸如more、less、vi和emacs之类的程序对终端设置做一些奇怪的事情。不考虑从shell中运行这些程序。坚持简单的基于文本的程序,如/bin/ls,/bin/ps,/bin/echo.

当您从标准Unix shell运行您的shell时,您的shell正在前台进程组中运行如果您的shell随后创建了一个子进程,默认情况下,该子进程也是前台进程组。

 因为按ctrl-c会向前台组的每个进程发送一个SIGINT,键入ctrl-c将向你的shell以及你的shell的每个子进程发送一个SIGINT。这显然是不正确的。

下面是解决方案:

  在fork之后,但在execve之前,子进程应该调用setpgid(0,0),它将子进程放入一个新的进程组中,该进程组的组ID与孩子的PID相同。

这确保前台进程组中只有一个进程,即你的shell。

当您键入ctrl-c时,shell应该捕获生成的SIGINT,然后转发它到适当的前台作业

 

eval()函数的原型可以在P503找到

 1 void eval(char *cmdline)
 2 {
 3     char *argv[MAXLINE];    /*argument list of execve()*/
 4     char buf[MAXLINE];      /*hold modified commend line*/
 5     int bg;                 /*should the job run in bg or fg?*/
 6     pid_t pid;
 7     sigset_t mask;          /*mask for signal*/
 8 
 9     stpcpy(buf,cmdline);
10     bg = parseline(buf,argv);
11 
12     if(argv[0]==NULL){
13         return;     /*ignore empty line*/
14     }
15 
16     if(!builtin_cmd(argv)){                         /*not a build in cmd*/
17         Sigemptyset(&mask);
18         Sigaddset(&mask,SIGCHLD);
19         Sigprocmask(SIG_BLOCK,&mask,NULL);           /*block the SIGCHLD signal*/
20 
21         if((pid = Fork())==0)
22         {
23             Sigprocmask(SIG_UNBLOCK,&mask,NULL);     /*unblock the SIGCHLD signal in child*/
24             Setpgid(0,0);                            /*puts the child in a new process group*/
25 
26             if(execve(argv[0],argv,environ)<0){
27                 printf("%s: Command not found\n",argv[0]);
28                 exit(0);
29             }
30         }
31 
32         addjob(jobs, pid, bg?BG:FG,cmdline);        /*add job into jobs*/
33         Sigprocmask(SIG_UNBLOCK,&mask,NULL);        /*unblock the SIGCHLD signal in parent*/
34 
35         bg ? printf("[%d] (%d) %s", pid2jid(pid), pid,cmdline):waitfg(pid); /*do in background or foreground*/
36     }
37     return;
38 }

猜你喜欢

转载自www.cnblogs.com/zhibin123/p/10459433.html
今日推荐