【HIT-计算机系统】ICS-Lab7 TinyShell

第1章 实验基本信息

1.1 实验目的

理解现代计算机系统进程与并发的基本知识;

掌握linux 异常控制流和信号机制的基本原理和相关系统函数;

掌握shell的基本原理和实现方法;

深入理解Linux信号响应可能导致的并发冲突及解决方法;

培养Linux下的软件系统开发与测试能力。

1.2 实验环境与工具

1.2.1 硬件环境

x64 CPU;1.60GHz;8G RAM;256GHD Disk。

1.2.2 软件环境

Windows10 64位。

1.2.3 开发工具

VM VirtualBox 6.1;Ubuntu 20.04 LTS 64位;

Visual Studio 2019 64位;CodeBlocks 17.12 64位;vi/vim/gedit+gcc。

1.3 实验预习

见第二章

第2章 实验预习

总分20

2.1 进程的概念、创建和回收方法(5分)

进程的经典定义是一个执行中程序的实例,系统中的每个程序都运行在某个进程的上下文中。上下文是由程序正确运行所需的状态组成的。这个状态包括存放在内存中的程序的代码和数据,它的栈、通用目的寄存器的内容、程序计数器、环境变量以及打开文件描述符的集合。

每次用户通过向shell输入一个可执行目标文件的名字,运行程序时,shell会创建一个新的进程,然后在这个新进程的上下文中运行这个可执行目标文件。应用程序也能够创建新进程,并且在这个新进程的上下文中运行它们自己的代码或其他应用程序。

父进程通过调用fork函数创建一个新的运行的子进程。

当一个进程由于某种原因终止时,内核并不是立即把它从系统中清除。相反,进程被保持在一种已终止的状态中,直到它被父进程回收。当父进程回收已终止的子进程时,内核将子进程的退出状态传递给父进程,然后抛弃已终止的进程,从此时开始,该进程就不存在了。如果一个父进程终止了,内核会安排init进程成为它的孤儿进程的养父。

2.2信号的机制、种类(5分)

一个信号就是一条小消息,它通知进程系统中发生了一个某种类型的事件。

每种信号类型都对应于某种系统事件,底层的硬件异常是由内核异常处理程序处理的,正常情况下,对用户进程而言是不可见的。信号提供了一种机制,通知用户进程发生了这些异常。

信号种类

2.3 信号的发送方法、阻塞方法、处理程序的设置方法(5分)

1.发送方法

(1)/bin/kill程序发送信号

/ bin / ki11 程序可以向另外的进程发送任意的信号。比如,命令

linux> / bin/ kill -9 15213

发送信号9(SIGKILL) 给进程15213 。一个为负的PID 会导致信号被发送到进程组PID 中的每个进程。比如,命令

1inux > /bin/ki11 -9 -5213

发送一个SIGKILL 信号给进程组15213 中的每个进程。注意,在此我们使用完整路径/bin / kill,因为有些Unix shell 有自己内置的kill 命令。

(2)从键盘发送信号

Unix shell 使用作业(job)这个抽象概念来表示为对一条命令行求值而创建的进程。在任何时刻,至多只有一个前台作业和0 个或多个后台作业。比如,键入

linux> 1s / sort

会创建一个由两个进程组成的前台作业,这两个进程是通过Unix 管道连接起来的:一个进程运行ls 程序,另一个运行sort 程序。shell 为每个作业创建一个独立的进程组。进程组ID 通常取自作业中父进程中的一个。

(3)kill函数发送信号

(4)alarm函数发送信号

2.阻塞方法

Linux提供阻塞信号的隐式和显式的机制:

隐式阻塞机制:内核默认阻塞任何当前处理程序正在处理信号类型的待处理的信号。

显式阻塞机制:应用程序可以使用sigprocmask 函数和它的辅助函数,明确地阻塞和解除阻塞选定的信号。

3.处理程序设置方法

signal 函数可以通过下列三种方法之一来改变和信号signum 相关联的行为:

如果handler是SIG_IGN ,那么忽略类型为signum的信号。

如果handler 是SIG_DFL ,那么类型为signum的信号行为恢复为默认行为。

否则,handler就是用户定义的函数的地址,这个函数被称为信号处理程序,只要进程接收到一个类型为signum的信号,就会调用这个程序。通过把处理程序的地址传递到signal 函数从而改变默认行为,这叫做设置信号处理程序(installing the handler)。调用信号处理程序被称为捕获信号。执行信号处理程序被称为处理信号。

当一个进程捕获了一个类型为k的信号时,就会调用为信号设置的处理程序, 一个整数参数被设置为k,这个参数允许同一个处理函数捕获不同类型的信号。

当处理程序执行它的return 语句时,控制(通常)传递回控制流中进程被信号接收中断位置处的指令。我们说“通常”是因为在某些系统中,被中断的系统调用会立即返回一个错误。

2.4 什么是shell,功能和处理流程(5分)

在计算机科学中,Shell俗称壳(用来区别于核),是指"为使用者提供操作界面"的软件(命令解析器)。它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。

shell负责确保用户在命令提示符后输入的命令被正确执行。其功能包括:
(1) 读取输入并解析命令行
(2) 替换特别字符,比如通配符和历史命令符
(3) 设置管道、重定向和后台处理
(4) 处理信号
(5) 程式执行的相关设置

处理流程:

1.  Shell首先从命令行中找出特殊字符(元字符),在将元字符翻译成间隔符 号。元字符将命令行划分成小块tokens。Shell中的元字符如下所示: 
SPACE , TAB , NEWLINE , & , ; , ( , ) ,< , > , | 
2.程序块tokens被处理,检查看他们是否是shell中所引用到的关键字。 
3.当程序块tokens被确定以后,shell根据aliases文件中的列表来检查命令 的第一个单词。如果这个单词出现在aliases表中,执行替换操作并且处理过程 回到第一步重新分割程序块tokens。

4.Shell对~符号进行替换。 
5.Shell对所有前面带有$符号的变量进行替换。 
6.Shell将命令行中的内嵌命令表达式替换成命令;他们一般都采用$(command) 标记法。 
7.Shell计算采用$(expression)标记的算术表达式。 
8.Shell将命令字符串重新划分为新的块tokens。这次划分的依据是栏位分割 符号,称为IFS。缺省的IFS变量包含有:SPACE , TAB 和换行符号。 
9.Shell执行通配符* ? [ ]的替换。 
10.shell把所有从处理的结果中用到的注释删除,並且按照下面的顺序实行命 令的检查: 
A.内建的命令 
B. shell函数(由用户自己定义的) 
C.可执行的脚本文件(需要寻找文件和PATH路径) 
11.在执行前的最后一步是初始化所有的输入输出重定向。 

12.最后,执行命令。 

第3章 TinyShell的设计与实现

总分45

3.1 设计

3.1.1 void eval(char *cmdline)函数(10分)

函数功能:处理用户输入的命令行。

参    数:用户输入的命令行。

处理流程:先使用parseline()分解命令行,得到有效的输入参数,然后使用 builtin_cmd函数判断命令行是否为内置命令:若是,则使用builtin_cmd 处理;若不是,则fork子进程然后执行execve创建新的进程。

要点分析:在eval中,父进程必须在用fork创建子进程前,使用sigprocmask阻塞 SIGCHLD信号,防止父进程刚刚创建完成子进程,子进程在未被加入 到joblist时就被回收,这会在后面在列表中删除子进程造成异常;父 进程创建完成子进程并用addjob记录后,用 sigprocmask解除阻塞。子 进程从父进程处继承了信号阻塞向量,子进程必须确保在执行新程序 之前解除对SIGCHLD的阻塞。

3.1.2 int builtin_cmd(char **argv)函数(5分)

函数功能:判断命令行输入是否为内置命令,若是,则直接进行处理,若能返回 到eval则返回1,若不是,则返回0。

参    数:使用parse()分解命令行输入得到的参数

处理流程:分别判断命令行参数是否为内置命令,“quit”“bg”“fg”“jobs”, 然后分别跳转到各自的执行程序:其中“quit”直接退出程序;“bg” 和“fg”使用函数do_bgfg进行处理,处理完毕后返回1;“jobs”使 用job的辅助操作函数listjobs列出job列表,成功后返回1;若不是 这些内置函数则返回0。

要点分析:非结束进程的处理程序结束后不要忘记return 1。

不要在do_bgfg附近设计信号阻塞,这会阻止shell接受SIGCONT信 号,从而导致命令fg,bg失效。

3.1.3 void do_bgfg(char **argv) 函数(5分)

函数功能:处理内置命令bg,fg命令

参    数:使用parse()分解命令行输入得到的参数

处理流程:首先根据%后面的数字得到joblist中相应的进程,然后根据fg\bg命令 进行不同的处理:若为fg则将该进程转为前台进程,即将进程的状态 改为FG,并显式地等待其结束;若为bg则将该进程转为后台进程, 即将该进程地状态改为BG,然后输出该进程状态。

要点分析:不要在do_bgfg附近设计信号阻塞,这会阻止shell接受SIGCONT信 号,导致命令fg,bg失效。

3.1.4 void waitfg(pid_t pid) 函数(5分)

函数功能:显式地等待前台进程结束。

参    数:待等待的进程pid。

处理流程:先记下该进程的job结构体地址,进行busy loop等待该地址下的job 被clearjob清除。

要点分析:需要先记下等待进程的job结构体地址,否则若在while判断语句中使 用getjobpid会导致在job被从joblist删除后找不到地址而出现段异常。

3.1.5 void sigchld_handler(int sig) 函数(10分)

函数功能:SIGCHLD信号处理程序,在接收到SIGCHLD后回收所有僵死子进程。

参    数:接收到的信号。

处理流程:首先使用while(waitpid(-1,&status,WNOHANG|WUNTRACED)>0)特定 的顺序回收所有僵死子进程,然后在循环体内进行信号类型的判断和 提示的输出。若进程由于正常退出而终止,则直接将其从joblist中删 除;若进程由于其他信号而被杀死,则打印提示信息后将其从joblist 中删除;若进程由于信号停止,则将其状态改为ST。

要点分析:在进程回收时循环体内处理时需要阻塞相关信号,防止在更改job的相 关成员信息时,由于其他信号的中断城改造成错误。

不要使用unix_error处理errno=ECHILD的情况,我们持续对子进程进 行回收,这必会导致回收结束时waitpid返回-1,并设置errno为 ECHILD,若使用unix_error(“waitpid error”)必会主动造成waitpid error:interrupted system call异常的出现。

3.2 程序实现(tsh.c的全部内容)(10分)

重点检查代码风格:

  1. 用较好的代码注释说明——5
  2. 检查每个系统调用的返回值——5分

 见github仓库内源代码文件

第4章 TinyShell测试

总分15

4.1 测试方法

针对tsh和参考shell程序tshref,完成测试项目4.1-4.15的对比测试,并将测试结果截图或者通过重定向保存到文本文件(例如:./sdriver.pl -t trace01.txt -s ./tsh -a "-p" > tshresult01.txt),并填写完成4.3节的相应表格。

4.2 测试结果评价

tsh与tshref的输出在以下两个方面可以不同:

(1)pid

(2)测试文件trace11.txt, trace12.txt和trace13.txt中的/bin/ps命令,每次运行的输出都会不同,但每个mysplit进程的运行状态应该相同。

除了上述两方面允许的差异,tsh与tshref的输出相同则判为正确,如不同则给出原因分析。

4.3 自测试结果

填写以下各个测试用例的测试结果,每个测试用例1分。

4.3.1测试用例trace01.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.2测试用例trace02.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.3测试用例trace03.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.4测试用例trace04.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.5测试用例trace05.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.6测试用例trace06.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.7测试用例trace07.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.8测试用例trace08.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.9测试用例trace09.txt

tsh测试结果

tshref测试结果

测试结论

相同

4.3.10测试用例trace10.txt 

tsh测试结果

tshref测试结果

测试结论

相同

4.3.11测试用例trace11.txt

测试中ps指令的输出内容较多,仅记录和本实验密切相关的tsh、mysplit等进程的部分信息即可。

tsh测试结果

tshref测试结果

测试结论

相同

4.3.12测试用例trace12.txt

测试中ps指令的输出内容较多,仅记录和本实验密切相关的tsh、mysplit等进程的部分信息即可。

tsh测试结果

tshref测试结果

测试结论

相同

4.3.13测试用例trace13.txt

测试中ps指令的输出内容较多,仅记录和本实验密切相关的tsh、mysplit等进程的部分信息即可。

tsh测试结果

tshref测试结果

测试结论

相同

4.3.14测试用例trace14.txt

tsh测试结果

tshref测试结果

测试结论

相同

 4.3.15测试用例trace15.txt

tsh测试结果

tshref测试结果

测试结论

相同

代码、附件github地址

https://github.com/ChenDolph7in/HITICS-LABS-in-21-Spring/tree/master/Lab7

  • 3
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值