《深入理解计算机系统》实验六Shell Lab 下载和官方文档机翻

前言

《深入理解计算机系统》官网:http://csapp.cs.cmu.edu/3e/labs.html
该篇文章是
实验六Shell Lab的Writeup(shlab.pdf)机翻
原文:http://csapp.cs.cmu.edu/3e/shlab.pdf

在官网点击下方即可下载实验六的文件
在这里插入图片描述

介绍

这次作业的目的是要更熟悉过程控制和信令的概念。您将通过编写一个支持作业控制的简单Unix shell程序来实现这一点。

组织工作

你们可以组成一组,最多两个人来解决这个作业的问题。唯一的“提交”将是电子的。任何对作业的澄清和修改将在课程网页上公布。

发指令

特定地点:在这里插入一段解释讲师将如何向学生分发shlab-handout.tar文件。这是我们在CMU使用的指导。
首先将文件shlab-handout.tar复制到您计划执行工作的受保护目录(lab目录)。然后执行以下操作

  • 输入命令tar xvf shlab-handout.tar展开tarfile。
  • 键入命令make来编译和链接一些测试例程。
  • 在tsh.c顶部的标题注释中输入您的团队成员名称和Andrew id。

查看tsh.c(微型shell)文件,您将看到它包含一个简单Unix shell的函数框架。为了帮助您入门,我们已经实现了一些不太有趣的函数。您的任务是完成下面列出的剩余空函数。为了检查您的完整性,我们在参考解决方案(包括许多注释)中列出了每个函数的大约代码行数。

  • eval:解析和解释命令行的主例程。[70行]
  • builtin_cmd:识别并解释内置命令:quit、fg、bg和jobs。[25行]
  • do_bgfg: Implements the bg and fg built-in commands. [50 lines]
  • waitfg:等待前台任务完成。[20行]
  • sigchld_handler:捕获SIGCHILD信号。[80行]
  • sigint_handler:捕获SIGINT (ctrl-c)信号。[15行]
  • sigtstp_handler: 捕获SIGTSTP (ctrl-z)信号。[15行]

每次修改tsh.c文件时,输入make以重新编译它。要运行shell,在命令行输入tsh:
在这里插入图片描述

Unix shell概述

shell是一个交互式的命令行解释器,它代表用户运行程序。shell重复地打印一个提示符,在stdin上等待一个命令行,然后按照命令行内容的指示执行一些操作。

命令行是一个由空格分隔的ASCII文本单词序列。命令行中的第一个单词要么是内置命令的名称,要么是可执行文件的路径名。其余的单词是命令行参数。如果第一个单词是一个内置命令,shell会立即在当前进程中执行该命令。否则,该字被假定为可执行程序的路径名。在这种情况下,shell派生一个子进程,然后在该子进程的上下文中加载和运行程序。由于解释单个命令行而创建的子进程统称为一个作业。通常,一个作业可以由Unix管道连接的多个子进程组成。

如果命令行以&号“&”结束,那么作业将在后台运行,这意味着shell在打印提示符并等待下一个命令行之前不会等待作业结束。否则,作业将在前台运行,这意味着shell将在等待下一个命令行之前等待作业终止。因此,在任何时间点,最多只能有一个作业在前台运行。但是,可以在后台运行任意数量的作业。例如,输入命令行
在这里插入图片描述
使shell执行内置的jobs命令。输入命令行
在这里插入图片描述
在前台运行ls程序。根据约定,当程序开始执行它的主例程时,shell确保
int main(int argc, char *argv[])

argc和argv参数有以下值:

  • argc == 3
  • argv[0] == ‘’/bin/ls’’
  • argv[1] == ‘’-l’’
  • argv[2] == ‘’-d’’

argc和argv参数有以下值:
在这里插入图片描述
在后台运行ls程序。
Unix shell支持作业控制的概念,它允许用户在后台和前台之间来回移动作业,并更改作业中进程的状态(运行、停止或终止)。输入ctrl-c会向前台作业中的每个进程发送一个SIGINT信号。SIGINT的默认操作是终止进程。类似地,键入ctrl-z将导致向前台作业中的每个进程发送SIGTSTP信号。SIGTSTP的默认操作是将进程置于停止状态,直到收到SIGCONT信号将其唤醒。Unix shell还提供支持作业控制的各种内置命令。例如:

  • jobs:列出正在运行和已停止的后台作业。
  • bg :将一个已停止的后台作业修改为正在运行的后台作业。
  • fg :将一个已停止或正在运行的后台作业更改为正在前台运行的作业
  • kill :终止作业。

tsh规范

你的tsh shell应该具有以下特性:

  • 提示符应该是字符串“tsh>”。
  • 用户键入的命令行应该由一个名称和零个或多个参数组成,所有参数之间用一个或多个空格分隔。如果name是一个内置命令,那么tsh应该立即处理它并等待下一个命令行。否则,tsh应该假定名称是可执行文件的路径,它将在初始子进程的上下文中加载并运行该可执行文件(在此上下文中,术语job指的是这个初始子进程)。
  • tsh不需要支持管道(|)或I/O重定向(<和>)。
  • 输入ctrl-c (ctrl-z)应该会导致一个SIGINT (SIGTSTP)信号被发送到当前前台作业,以及该作业的任何后代(例如,它分叉的任何子进程)。如果没有前台作业,那么信号应该没有效果。
  • 如果命令行以&结束,那么tsh应该在后台运行该作业。否则,它应该在前台运行作业。
  • 每个作业可以通过进程ID (PID)或作业ID (JID)来标识,JID是由tsh分配的正整数。jid应该在命令行中用前缀’ % '表示。例如,“%5”表示JID 5,“5”表示PID 5。(我们已经为您提供了操作作业列表所需的所有例程。)
  • TSH应该支持以下内置命令:
    • quit命令终止shell。
    • jobs命令列出所有后台任务。
    • bg 命令通过发送SIGCONT信号来重启,然后在后台运行它。参数可以是PID或JID。
    • fg 命令通过发送SIGCONT信号来重启,然后在前台运行它。参数可以是PID或JID。
  • TSH应该收获它所有的僵尸孩子。如果任何一个作业因为它接收到一个它没有捕捉到的信号而终止,那么tsh应该识别这个事件,并使用作业的PID和对违规信号的描述打印一条消息。

检查你的工作

我们提供了一些工具来帮助您检查您的工作。
参考解决方案(Reference solution.).Linux可执行文件tshref是shell的参考解决方案。运行此程序以解决有关shell应该如何运行的任何问题。您的shell应该发出与引用解决方案相同的输出(当然,pid除外,它在每次运行时都会发生变化)。
Shell 驱动程序(Shell driver). sdriver.pl程序将shell作为子进程执行,根据跟踪文件的指示向它发送命令和信号,并捕获和显示shell的输出。
使用-h参数找出sdriver.pl的用法:
在这里插入图片描述
我们还提供了16个跟踪文件(trace{01-16}.txt),您将与shell驱动程序一起使用它们来测试shell的正确性。编号较低的跟踪文件执行非常简单的测试,编号较高的测试执行更复杂的测试。
你可以在你的shell上使用跟踪文件trace01.txt(例如)运行shell驱动程序,输入:
在这里插入图片描述
(-a "-p"参数告诉你的shell不发出提示符),或者
在这里插入图片描述
类似地,要将你的结果与引用shell进行比较,你可以在引用shell上运行跟踪驱动程序,输入:
在这里插入图片描述
或者
在这里插入图片描述
供参考,tshref.out给出了所有竞赛的参考解决方案的输出。这可能比在所有跟踪文件上手动运行shell驱动程序更方便。
跟踪文件的巧妙之处在于,它们生成的输出与您交互运行shell时得到的输出相同(除了标识跟踪的初始注释之外)。例如:
在这里插入图片描述
在这里插入图片描述

提示

  • 阅读课本第八章(异常控制流)的每一个字。
  • 使用跟踪文件来指导shell的开发。从trace01.txt开始,确保您的shell产生与参考shell相同的输出。然后继续跟踪文件trace02.txt,等等。
  • waitpid、kill、fork、execve、setpgid和sigprocmask函数将非常方便。waitpid的WUNTRACED和WNOHANG选项也很有用。
  • 当你实现你的信号处理程序时,一定要向整个前台进程组发送SIGINT和SIGTSTP信号,在kill函数的参数中使用" -pid “而不是” pid "。sdriver.pl程序会测试这个错误。
  • 赋值的一个棘手部分是决定在waitfg和sigchld_handler函数之间分配工作。我们建议采用以下方法:
    • 在waitfg中,在sleep函数周围使用一个繁忙的循环。
    • 在sigchld_handler中,对waitpid只使用一次调用。
      虽然也有其他的解决方案,比如在waitfg和sigchld处理程序中同时调用waitpid,但这些可能会非常令人困惑。在处理程序中执行所有的收割操作更简单。
  • 在eval中,父进程在分叉子进程之前必须使用sigprocmask来阻塞SIGCHLD信号,然后再解除这些信号的阻塞,在通过调用addjob将子进程添加到作业列表之后再次使用sigprocmask。因为子程序继承了父程序的阻塞向量,所以子程序必须确保在执行新程序之前解除阻塞SIGCHLD信号。
    父进程需要以这种方式阻止SIGCHLD信号,以避免在父进程调用addjob之前,SIGCHLD处理器获取子进程(从而从任务列表中删除)的竞争状态。
  • 像more、less、vi和emacs这样的程序会对终端设置做一些奇怪的事情。不要从您的shell运行这些程序。坚持使用简单的基于文本的程序,如/bin/ls,/bin/ps和/bin/echo。
  • 当您从标准Unix shell运行您的shell时,您的shell运行在前台进程组中。如果您的shell随后创建了一个子进程,默认情况下,该子进程也将是前台进程组的成员。因为键入ctrl-c会向前台组中的每个进程发送一个SIGINT,键入ctrl-c会向您的shell发送一个SIGINT,以及您的shell创建的每个进程,这显然是不正确的。
    下面是解决方法:在fork之后,但是在execve之前,子进程应该调用setpgid(0,0),这将把子进程放到一个新进程组中,该进程组ID与子进程的PID相同。这将确保前台进程组中只有一个进程,即您的shell进程。当您键入ctrl-c时,shell应该捕获生成的SIGINT,然后将其转发给适当的前台作业(或者更准确地说,转发给包含前台作业的进程组)。

评价

您的分数将根据以下分布计算,最高90分:
80 正确性:每5个点有16个跟踪文件。
10 风格点。我们希望你有好的评论(5点),并检查每个系统调用的返回值(5点)。

您的解决方案shell将在Linux机器上进行正确性测试,使用实验室目录中包含的相同shell驱动程序和跟踪文件。你的shell应该在这些跟踪中产生与参考shell相同的输出,只有两个例外:

  • pid可以(也将)是不同的。
  • “trace11.txt”、“trace12.txt”和“trace13.txt”中的/bin/ps命令的输出与“run”不同。但是,在/bin/ps命令的输出中,任何mysplit进程的运行状态都应该是相同的。

交指令

特定地点:在这里插入一段解释学生应该如何提交他们的tsh.c文件。这是我们在CMU使用的指导。

  • 确保在tsh.c的头注释中包含了您的姓名和Andrew id。
  • 创建表单的团队名称:
    • “ID”,其中ID是您的Andrew ID,如果您是单独工作,或
    • ID1+ID2”,其中ID1是第一个团队成员的Andrew ID, ID2是第二个团队成员的Andrew ID。
      我们需要你以这种方式创建你的团队名称,以便我们可以自动评级你的作业。
  • 要提交你的tsh.c文件,输入:
    make handin TEAM=teamname
    其中teamname是上面描述的团队名称。
  • 在提交后,如果你发现一个错误,并想要提交一份修改后的副本,键入
    make handin TEAM=teamname VERSION=2
    每次提交都要增加版本号。
  • 你应该向里面看,以核实你交的东西
    /afs/cs.cmu.edu/academic/class/15213-f01/L5/handin
    您在此目录中具有列表和插入权限,但没有读或写权限。

好运!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值