CSAPP:ShellLab实验

前言

  • 本实验是《深入理解计算机系统》一书中的附带实验,也称外壳实验。在本次实验中,学生们实现他们自己的带有作业控制的Unix外壳程序,包括ctrl-cctrl-z按键、fg、bg和jobs命令。这是学生们第一次接触并发,并且让他们对Unix的进程控制、信号和信号处理有清晰的了解。
  • 本文用于记录之前做实验的一些信息,可能思路有些凌乱,谨慎参考

任务一

学会编译tsh.c,调用tsh文件traceXX.txt的功能验证方法

  1. 使用make命令编译tsh.c文件(文件有所改变的话需要先使用make clean指令清空)
    在这里插入图片描述
  2. 使用make testXXmake rtestXX指令比较traceXX.txt文件在编写的shell和reference shell的运行结果;或者也可以使用”./sdriver.pl -t traceXX.txt -s ./tsh -a “-p”和”./sdriver.pl -t traceXX.txt -s ./tshref -a “-p”

用trace01和trace02比较tsh和tshref执行结果并分析

  1. 输入make test01make rtest01查看执行结果;trace01.txt文件中只有CLOSE,WAIT两条命令,在EOF上正常终止,tsh和tshref执行结果相同
    在这里插入图片描述
    在这里插入图片描述
  2. 输入make test02make rtest02查看执行结果;trace02.txt文件中只有quit,WAIT两条命令,由于tsh的quit内置命令还未编写,所以不能正常退出,而tshref可以
    在这里插入图片描述
    在这里插入图片描述

任务二

  1. 编程实现quit内置命令,补齐文件tsh.c中的函数eval()函数和函数built-cmd()与quit相关的部分
    在这里插入图片描述
    首先从命令中提取参数,然后判断是否为内置命令,如果为内置命令,则直接在当前进程执行即可;如果不是内置命令,则需要新建一个子进程,并利用 execve 来通过参数给出的路径寻找出可执行文件并在子进程中执行,如果找不到该可执行文件,则输出命令未找到,并结束子进程。

使用trace03验证quit命令
在这里插入图片描述
在这里插入图片描述

  1. 首先是/bin/echo tsh> quit 意思是打开 bin 目录下的 echo 可执行文件,在 foregound 开启一个子进程运行它(因为末尾没有&符号,如果有,就是在 backgound 运行)
  2. 运行 echo 这个进程的过程中,通过 tsh>quit 命令,调用 tsh并执行内置命令 quit,退出 echo 这个子进程
  3. 最后在 tsh 中执行内置命令 quit,退出 tsh 进程,回到我们的终端。
    trace03.txt中的内置命令是quit命令,tsh能够正常执行,且与tshref的结果一致

了解eval()与execve()执行流程和fork()多进程运行方式:

  1. 首先执行 eval(),在 eval中发现如果命令不是内置命令,则会调用 fork()函数来新建一个子进程,在子进程中调用 execve()函数通过 argv[0]来寻找路径,并在子进程中运行路径中的可执行文件,如果找不到可执行文件,则说明命令为无效命令,输出命令无效,并用 exit(0)结束该子进程即可。

任务三

了解tsh.c中作业表job struct和操作管理函数(如addjob()
编程实现eval()的后台作业管理功能并使用trace04验证

  1. 在原有eval函数的基础之上添加了将作业添加至后台作业管理的函数使用。创建了子进程:
    在这里插入图片描述
  2. 使用trace04.txt验证可以确定查看得到结果和标准一致(作业号均为1,只是进程号不同)
    在这里插入图片描述
  3. 学习trace测试文件符号(空格、&、#等)、命令、用户程序myspin含义
    1)文件符号:
    空格:用来分隔命令和参数或者参数与参数;
    &:如果一个命令以&结尾,shell应该在后台运行它,否则在前台运行;
    #:以 # 开头的行就是注释,会被解释器忽略。
    2)命令:
    包括内建命令和外部命令。内置命令包括quit、jobs、bg、fg等等。
    在这里插入图片描述
    在这里插入图片描述
    可以使用type来确定一个命令是否是内置命令。由此可见,cd 是一个 Shell 内建命令,而 ifconfig 是一个外部文件,它的位置是/sbin/ifconfig。通常来说,内置命令会比外部命令执行得更快,执行外部命令时不但会触发磁盘 I/O,还需要 fork 出一个单独的进程来执行,执行完成后再退出。而执行内建命令相当于调用当前 Shell 进程的一个函数。

用户程序myspin:使用myspin 指令可将进程挂起n秒,具体分析见下图:
在这里插入图片描述

任务四

  1. 编程实现jobs内建命令,使用trace05验证
    在原有builtin_cmd函数中添加一个判断函数,如果参数是jobs,则执行listjobs函数的功能(即将所有的作业打印出来)
    在这里插入图片描述
    如下为listjobs函数的内容
    在这里插入图片描述
    在这里插入图片描述
    标明最大作业量为16
    定义一个作业的结构体,该结构体具有的属性有作业的作业号、进程号、状态、命令行参数
    在这里插入图片描述
    使用下列函数进行清空作业/初始化作业/最大作业号/添加作业/删除作业等功能
    在这里插入图片描述
    经过make test05命令对其进行验证,发现和make rtest05运行得到的结果一致,故成功实现其功能

在这里插入图片描述

任务五

  1. 比较trace06执行不同结果,编程实现sigint_handler捕获INT响应、waitfg()等待、sigchld_handler回收僵死
    在没有进行修改之前trace06执行得到的不同结果如图所示,test06中找不到进程
    在这里插入图片描述
    Sigint_handler捕获INT响应:
    在这里插入图片描述
    Waitfg()等待:
    在这里插入图片描述
    Sigchld_handler回收僵死:
    在这里插入图片描述
    1. 验证trace06~07,了解接收信号、信号处理、信号阻塞概念
      接收信号:当目的进程被内核强迫以方式对信号的发送做出反应时,目的进程就 接收了信号。进程可以忽略这个信号,终止或者通过执行一个称为信号处理 程序的用户层函数捕获这个信号。
      信号处理:signal函数可以通过下列三种方法之一来改变和信号signum相关联的行为:
      ①如果handler是SIG_IGN,那么忽略类型为signum的信号;
      ②如果handler是SIG_DFL,那么类型为signum的信号行为恢复为默认模式;
      ③否则,handler就是用户定义的函数的地址,这个函数称为信号处理程序,
      当一个程序要捕获多个信号时,会有以下问题:
      ①待处理信号被阻塞;②待处理信号不会排队等待;③系统调用可以被中断。
      信号阻塞:Unix信号处理程序通常会阻塞当前处理程序正在处理类型的待处理信号。

验证trace06可以看出tsh和tsh-ref实现的功能一致
在这里插入图片描述
验证trace07可以看出tsh和tsh-ref实现的功能一致
在这里插入图片描述

任务六

  1. 比较trace08执行不同结果,编程实现sigtstp_handler捕获TSTP响应
    在没有进行修改之前trace08执行得到的不同结果如图所示
    在这里插入图片描述
    Sigtstp_handler函数
    在这里插入图片描述
  2. 验证trace08
    验证trace08可以看出tsh和tsh-ref实现的功能一致
    在这里插入图片描述

任务七

  1. 比较trace09~10执行不同结果,编程实现内建命令bg和fg的do_bgfg()处理函数
    Trace09
    在这里插入图片描述
    trace10
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 验证trace09~10
    在trace09中执行完bg %2命令后会将作业2放到后台运行,故最终【2】后面会显示running;在trace10中执行fg %1会将后台的作业1停止之后添加到前台运行
    在这里插入图片描述
    在这里插入图片描述
    经过验证之后可知,tsh.c与tsh-ref运行结果一致

任务八

  1. 验证trace11~15并解释与记录
    Trace11:./mysplit 4创建子进程并将其挂起 4 秒,而父进程在挂起 2 秒后发送 SIGINT 信号使子进程终止
    在这里插入图片描述
    Trace12:./mysplit 4 创建子进程并将其挂起 4 秒,而父进程在挂起 2 秒后发送 SIGTSTP 信号使子进程停止直到下一个 SINCONT,因此执行 jobs 指令,可以看到子进程处 于 Stopped 状态,用 ps a 指令查看,./tsh –p 只运行了 2 秒。
    在这里插入图片描述
    Trace13:./mysplit 4 创建子进程并将其挂起 4 秒,而父进程在挂起 2 秒后发送 SIGTSTP 信号使子进程停止直到接收一个 SINCONT 信号,因此执行 jobs 指令,可以看到子 进程处于 Stopped 状态,用 ps a 指令查看,./tsh –p 只运行了 2 秒。然后执行 fg %1 指令, 将后台停止的作业 1 切换至前台运行,再次使用 ps a 指令查看,./tsh –p 运行 4 秒
    在这里插入图片描述
    在这里插入图片描述
    Trace14:处理输入未实现命令、fg 和 bg 参数不正确等错误情况
    Trace15:因为没有实现命令 bogus,所以执行./bogus 命令会报错。执行./myspin 10 命令,挂起 10 秒,但在挂起 2 秒后被 SIGINT 信号终止。./myspin 3 &和./myspin 4 &分 别在后台执行./myspin 3 和./myspin 4 命令,且前者作业号为 1,后者作业号为 2。此时使用 jobs 命令查看,两者都在后台运行。使用 fg %1 命令将作业 1 切换至前台运行,挂起 2 秒 后,发送 SIGTSTP 信号使其停止直到接收一个 SINCONT 信号。此时再次使用 jobs 命令查 看,发现作业 1 已经处于 Stopped 状态,而作业 2 仍然处于 Running 状态。因为没有作业 3,所以执行 bg %3 命令会报错。然后执行 bg %1 命令将已经在后台停止的作业 1 切换至运 行状态,即重启作业 1。此时使用 jobs 命令查看,作业 1 和作业 2 都处于后台运行状态。然后执行 fg %1 命令将作业从后台运行状态切换至前台运行状态。最后执行 quit 命令结束。
    在这里插入图片描述
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值