深入理解计算机系统实验日志(五)——Shell Lab

说明:本次实验是csapp的最后一个实验,其目标是自己实现一个shell以控制进程

—主要任务—

修改tsh.c文件补全以下七个函数:

  • eval:解析命令行语句并运行进程
  • builtin_cmd:判断是否是内建指令
  • do_bgfg:执行 bg < job > 和 fg < job > 内置命令
  • waitfg:等待 pid 进程不再是前台进程
  • sigchld_handler:回收所有可获得的僵死子进程
  • sigtstp_handler:响应 SIGTSTP(ctrl-z) 信号
  • sigint_handler:响应 SIGINT(ctrl-c) 信号
—文件概览—

其中已经提供给我们的函数有:

  • parseline - Parse the command line and build the argv array.
  • clearjob - Clear the entries in a job struct
  • initjobs - Initialize the job list
  • maxjid - Returns largest allocated job ID
  • addjob - Add a job to the job list
  • deletejob - Delete a job whose PID=pid from the job list
  • fgpid - Return PID of current foreground job, 0 if no such job
  • getjobpid - Find a job (by PID) on the job list
  • getjobjid - Find a job (by JID) on the job list
  • pid2jid - Map process ID to job ID
  • listjobs - Print the job list
—设计思路—
1.eval

(CSAPP中文版教材P525有提供部分代码)

满足以下要求:

  • 内建命令(quit, jobs, bg, fg):立刻执行
  • 否则:创建一个子进程,在子进程的上下文环境中运行

代码实现思路:

  1. 解析命令判断是否是内建语句;
  2. 如果不是,创建子进程
  3. 判断前后台运行:前台,等待子进程终止;后台,输出提示语句,格式参照trace4运行结果在这里插入图片描述

注意:

  1. 每个子进程必须拥有自己的进程组id,以便向子进程组发送信号。否则,所有的子进程与tsh shell进程为同一个进程组,发送信号时,前后台的子进程均会收到。—— 实现:在fork()之后的子进程中setpgid(0,0)

setpgid(pid_t pid, pid_t pgid):将进程pid的进程组改为pgid。如果pid是0,那么就是用当前进程的pid,如果pgid是0,那么就用pid。

  1. 在fork()新进程前后要阻塞SIGCHLD信号,防止出现竞争的同步错误。否则,可能会出现子进程先运行结束从jobs中删除,而deletejob什么都不做,因为父进程还没有把子进程添加到列表中;然后再执行父进程,调用addjob错误地把不存在的子进程添加到作业列表中,永远也不会被删除。(CSAPP中文版教材P541)

  2. 子进程继承了父进程的被阻塞集合,在调用execve之前,要先小心解除子进程中阻塞的SIGCHID信号。

void eval(char *cmdline) 
{
   
    char *argv[MAXLINE];/* Argument list execve() */   
    char buf[MAXLINE];  /* Holds modified command line */
    int bg;             /* Should the job run in bg or fg? */
    pid_t pid;
    sigset_t mask_one;

    strcpy(buf,cmdline);
    bg=parseline(buf,argv);
    if(argv[0]==NULL)
        return;         /* Ignore empty lines */

    if(!builtin_cmd(argv)){
   /* Child runs user job */
        sigemptyset(&mask_one);
        sigaddset(&mask_one,SIGCHLD);
        Sigprocmask(SIG_BLOCK,&mask,NULL);/* Block SIGCHLD */

        if((pid=fork())==0){
   
            sigprocmask(SIG_UNBLOCK,&mask_one,NULL);/* Unblock SIGCHID */
            setpgid(0,0);

            if(execve(argv[0],argv,environ)<0){
   
                printf("%s: Command not found\n",argv[0]);
                exit(0);
            }
        }
        /* Parent waits for foreground job to terminate */   
        addjob(jobs,pid,bg?BG:FG,cmdline);
        Sigprocmask(SIG_UNBLOCK,&mask,NULL);/* Unblock SIGCHID */
        bg?printf("[%d] (%d) %s",pid2jid(pid),pid,cmdline):waitfg(pid);
    }
    return;
}
2.builtin_cmd

判断命令行语句是否是内建指令quit, jobs, bg, fg

  • 是:立即执行(对于单独的“&”指令直接无视),返回1
  • 不是:返回0
int builtin_cmd(char **argv) 
{
   
    if(!strcmp(argv[0],"quit"))
        exit(0);
    if(!strcmp(argv[0],"bg")||!strcmp(argv[0],"fg")){
   
        do_bgfg(argv);
        return 1;
    }
    if(!strcmp(argv[0],"jobs")){
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值