哈工大计算机系统实验七——微壳
实验报告
实 验(七)
题 目 TinyShell
微壳
专 业 计算机类
学 号 xxxx
班 级 xxxx
学 生 xxxx
指 导 教 师 xxxx
实 验 地 点 xxxx
实 验 日 期 2019.12.4
计算机科学与技术学院
目 录
第1章 实验基本信息............................................................................................. - 4 -
1.1 实验目的......................................................................................................... - 4 -
1.2 实验环境与工具............................................................................................. - 4 -
1.2.1 硬件环境................................................................................................. - 4 -
1.2.2 软件环境................................................................................................. - 4 -
1.2.3 开发工具................................................................................................. - 4 -
1.3 实验预习......................................................................................................... - 4 -
第2章 实验预习..................................................................................................... - 6 -
2.1 进程的概念、创建和回收方法(5分)...................................................... - 6 -
2.2信号的机制、种类(5分).......................................................................... - 6 -
2.3 信号的发送方法、阻塞方法、处理程序的设置方法(5分).................. - 6 -
2.4 什么是shell,功能和处理流程(5分)................................................... - 6 -
第3章 TinyShell的设计与实现.................................................................... - 7 -
3.1.1 void eval(char *cmdline)函数(10分)................................................ - 7 -
3. 1.2 int builtin_cmd(char **argv)函数(5分).......................................... - 7 -
3. 1.3 void do_bgfg(char **argv) 函数(5分)............................................ - 7 -
3. 1.4 void waitfg(pid_t pid) 函数(5分)....................................................... - 7 -
3. 1.5 void sigchld_handler(int sig) 函数(10分)...................................... - 8 -
第4章 TinyShell测试.................................................................................... - 9 -
4.1 测试方法......................................................................................................... - 9 -
4.2 测试结果评价................................................................................................. - 9 -
4.3 自测试结果..................................................................................................... - 9 -
4.3.1测试用例trace01.txt的输出截图(1分)............................................ - 9 -
4.3.2测试用例trace02.txt的输出截图(1分)............................................ - 9 -
4.3.3测试用例trace03.txt的输出截图(1分).......................................... - 10 -
4.3.4测试用例trace04.txt的输出截图(1分).......................................... - 10 -
4.3.5测试用例trace05.txt的输出截图(1分).......................................... - 10 -
4.3.6测试用例trace06.txt的输出截图(1分).......................................... - 11 -
4.3.7测试用例trace07.txt的输出截图(1分).......................................... - 11 -
4.3.8测试用例trace08.txt的输出截图(1分).......................................... - 11 -
4.3.9测试用例trace09.txt的输出截图(1分).......................................... - 12 -
4.3.10测试用例trace10.txt的输出截图(1分)........................................ - 12 -
4.3.11测试用例trace11.txt的输出截图(1分)........................................ - 12 -
4.3.12测试用例trace12.txt的输出截图(1分)........................................ - 13 -
4.3.13测试用例trace13.txt的输出截图(1分)........................................ - 13 -
4.3.14测试用例trace14.txt的输出截图(1分)........................................ - 13 -
4.3.15测试用例trace15.txt的输出截图(1分)........................................ - 14 -
4.4 自测试评分................................................................................................... - 14 -
第4章 总结........................................................................................................... - 15 -
4.1 请总结本次实验的收获............................................................................... - 15 -
4.2 请给出对本次实验内容的建议................................................................... - 15 -
参考文献................................................................................................................. - 16 -
第1章 实验基本信息
1.1 实验目的
掌握 linux 异常控制流和信号机制的基本原理和相关 系统函数
深入理解 Linux 信号响应可能导致的并发冲突及解决方法
1.2 实验环境与工具
1.2.1 硬件环境
Windows7 64 位以上;VirtualBox/Vmware 11 以上;Ubuntu 16.04 LTS 64 位/ 优麒麟 64 位
1.2.2 软件环境
Windows7 64 位以上;VirtualBox/Vmware 11 以上;1.2.3 开发工具
1.2.3 开发工具
1.3 实验预习
上实验课前,必须认真预习实验指导书(PPT 或 PDF)
了解实验的目的、实验环境与软硬件工具、实验操作步骤,复习 与实验有关的理论知识。
熟知进程创建、回收的方法和相关系统函数 熟知信号机制和信号处理相关的系统函数
第2章 实验预习
总分20分
2.1 进程的概念、创建和回收方法(5分)
创建进程:使用fork函数,父进程调用fork函数创建一个新的运行的子进程,子进程得到和父进程用户及虚拟地址空间完全相同的一个副本。
2.2信号的机制、种类(5分)
信号的机制:一个信号就是一条消息,它通知进程系统中发生了一个某种类型的事件。每种信号类型都对应某种系统的事件。信号类型是用小整数ID来标识,每一个信号对应唯一的ID。
发送信号:内核通过更新目的进程上下文的某种状态,发送一个信号给目的进程。
接收信号:内核强迫目的进程以某种方式对信号的发送做出反应,则接收了这种信号。
2.3 信号的发送方法、阻塞方法、处理程序的设置方法(5分)
- 用/bin/kill程序发送信号,/bin/kill程序可以向另外的进程发送任意的信号
- 从键盘发送信号,在键盘上输入Ctrl+C会导致内核发送一个SIGINT信号到前台进程中的每个进程,默认情况下是终止前台作业
- 用kill函数发送信号给其他进程(包括他们自己)
- 使用alarm函数发送信号,进程可以通过调用 alarm 函数在指定 secs 秒后发送一个 SIGALRM 信号给调用进程。
隐式阻塞机制:内核默认阻塞任何当前处理程序正在处理信号类 和待处理信号。
显示阻塞进制:应用程序可以调用 sigprocmask 函数和它的辅助函 数,明确地阻塞和解除阻塞选定的信号。调用要求如下:
- 调用 signal 函数,调用 signal(SIG,handler),SIG 代表信号类型,handler 代表接收到 SIG 信号之后对应的处理程序。
- 因为 signal 的语义各有不同,所以我们需要一个可移植的信号处理函 数设置方法,Posix 标准定义了 sigaction 函数,它允许用户在设置信号
2.4 什么是shell,功能和处理流程(5分)
shell:shell是一个用c语言编写的程序,它是用户使用Linux的桥梁,shell既是一种命令语言,又是一种程序设计语言,shell是一种应用程序。
功能:shell应用程序提供了一个界面,用户通过访问这个界面访问操作系统内 核的服务。
5)shell 应该接受键盘输入信号,并对这些信号进行相应处理
第3章 TinyShell的设计与实现
3.1.1 void eval(char *cmdline)函数(10分)
- 首先调用 parseline 函数。将 cmdline 字符串切分为参数数组 argv,另外 parseline 函数返回 bg,可以得知该操作是否需要后台运行。
- 调用 buildin_cmd 判断该函数是否为内置函数。如果是内置函数则立即执 行。
- 如果不是内置函数,创建一个子进程,然后在子进程的上下文中运行命令 行要求运行的函数(调用 execve 函数)。
2) 父进程创建完成子进程并用 addjob 记录后,需要用 sigprocmask 解除阻塞。
3) 子进程从父进程继承了信号阻塞向量,所以子进程必须确保在执行新程序 之前接触对信号的阻塞。
5).整个过程中,需要仔细考虑显式阻塞的安排和设计,什么地方需要阻塞哪些信号。
原则1:在访问全局变量(jobs)必须阻塞所有信号,包括调用老师给的那些函数。由于这些函数基本都是使用for循环遍历完成功能的,所以,务必保证函数执行中不能被中断。
原则2:在一些函数或者指令有必须的前后执行顺序时,请阻塞,保证前一个函数调用完成后(比如必须先addjob,再deletejob)
3. 1.2 int builtin_cmd(char **argv)函数(5分)
函数功能:判断命令是否是内置指令,是的话立即执行,不是则返回,对单独的‘&’无视
2) 内置函数”bg” | “fg”,如果是则调用函数 do_fgbg。返回值 1,tsh 继续。
3)内置函数”jobs”,如果是则调用 listjobs 列出所有的 job 信息。返回值 1, tsh 继续。
4) 如果以上都不是,则不是内置函数,返回 0,tsh 会将它作为一个 job 处理。
分别对三种不同的情况调用相应的处理函数。填对参数。了解三种内 置函数的意义,注意只有 quit 是需要 exit(0)的,其他两种情况都需要返回 1,这是 tsh 会继续自己的处理流程。
3. 1.3 void do_bgfg(char **argv) 函数(5分)
- 首先对传入的命令行输入进行解析。首先 bg fg的调用有两种格式,对 这两种格式分别判断然后读入输入的 job pid,通过 pid 调用 getjobpid 获得 job。
- 如果是 bg 命令,向 job 所在的进程组发送 SIGCONT 信号,更改 job 的 state 为 BG。
3) 如果是 fg 命令, 向 job 所在的进程组发送 SIGCONT 信号,更改 job 的 state 为 FG,然后等待当前的程序运行直到当前的 job 不再是前台程 序。
1. 区分bg和fg命令,以及传入pid或者jid参数对应的进程的状态。前者if,后者switch就可以包括所用的情况
2. 注意用户输入错误处理,比如参数数量不够或者参数传入错误的情况
3. 对例外进行报错,分别有:命令为空,找不到 PID 的 job,不符合 bgfg 的格式,命令不是 bgfg。
4.按照 bgfg 命令的特性,我们需要向目标 job 所在的进程组发送 SIGCONT 信号,代表如果该进程组中的进程停止,则需要重新进行。
3. 1.4 void waitfg(pid_t pid) 函数(5分)
进行 while 循环,每次 循环 sleep 1 秒,while 的终止条件是前台程序的 PID 不再是 pid。
调用 fgpid 函数向 jobs 查询当前 state 是 FG 的 job 的 PID。
3. 1.5 void sigchld_handler(int sig) 函数(10分)
- 处理所有子进程集合中已经停止或终止的子进程。
- 3) 如果该子进程通过调用 exit 或者一个返回正常终止,则阻塞信号,删 除 job,恢复信号。
- 如果该子进程当前已经停止,向屏幕打印信息。
- 如果该当前子进程是因为一个未被捕获的信号终止的,则向屏幕打印 信息,阻塞信号,删除 job,恢复信号。
3) 因为在信号处理函数中可能会调用修改 errno 的函数,所以我们 需要保 存恢复 errono。
/** tsh - A tiny shell program with job control*1180800811张瑞豪* <Put your name and login ID here>*/#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <ctype.h>#include <signal.h>#include <sys/types.h>#include <sys/wait.h>#include <errno.h>/* Misc manifest constants */#define MAXLINE 1024 /* max line size */#define MAXARGS 128 /* max args on a command line */#define MAXJOBS 16 /* max jobs at any point in time */#define MAXJID 1<<16 /* max job ID *//* Job states */#define UNDEF 0 /* undefined */#define FG 1 /* running in foreground */#define BG 2 /* running in background */#define ST 3 /* stopped *//** Jobs states: FG (foreground), BG (background), ST (stopped)* Job state transitions and enabling actions:* FG -> ST : ctrl-z* ST -> FG : fg command* ST -> BG : bg command* BG -> FG : fg command* At most 1 job can be in the FG state.*//* Global variables */extern char **environ; /* defined in libc */char prompt[] = "tsh> "; /* command line prompt (DO NOT CHANGE) */int verbose = 0; /* if true, print additional output */int nextjid = 1; /* next job ID to allocate */char sbuf[MAXLINE]; /* for composing sprintf messages */struct job_t { /* The job struct */pid_t pid; /* job PID */int jid; /* job ID [1, 2, ...] */int state; /* UNDEF, BG, FG, or ST */char cmdline[MAXLINE]; /* command line */};struct job_t jobs[MAXJOBS]; /* The job list *//* End global variables *//* Function prototypes *//* Here are the functions that you will implement */void eval(char *cmdline);int builtin_cmd(char **argv);void do_bgfg(char **argv);void waitfg(pid_t pid);void sigchld_handler(int sig);void sigtstp_handler(int sig);void sigint_handler(int sig);/* Here are helper routines that we've provided for you */int parseline(const char *cmdline, char **argv);void sigquit_handler(int sig);void clearjob(struct job_t *job);void initjobs(struct job_t *jobs);int maxjid(struct job_t *jobs);int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline);int deletejob(struct job_t *jobs, pid_t pid);pid_t fgpid(struct job_t *jobs);struct job_t *getjobpid(struct job_t *jobs, pid_t pid);struct job_t *getjobjid(struct job_t *jobs, int jid);int pid2jid(pid_t pid);void listjobs(struct job_t *jobs);void usage(void);void unix_error(char *msg);void app_error(char *msg);typedef void handler_t(int);handler_t *Signal(int signum, handler_t *handler);/** main - The shell's main routine*//** shell的执行main函数*/int main(int argc, char **argv){char c;char cmdline[MAXLINE];int emit_prompt = 1; /* emit prompt (default) *//*将stderr重定位到stdout*/dup2(1, 2);/* 解析命令行 讨论命令参数*/while ((c = getopt(argc, argv, "hvp")) != EOF) {switch (c) {case 'h': /*打印帮助信息*/usage();break;case 'v': /* 打印格外调试信息*/verbose = 1;break;case 'p': /* 不打印prompt */emit_prompt = 0;break;default:usage();}}/* 注册自己编写的信号处理函数 */Signal(SIGINT, sigint_handler); /* ctrl-c */Signal(SIGTSTP, sigtstp_handler); /* ctrl-z */Signal(SIGCHLD, sigchld_handler); /* 终止 或者 子进程返回 *//*干净地杀死terminal*/Signal(SIGQUIT, sigquit_handler);/*初始化工作列表*/initjobs(jobs);/* 执行死循环流程*/while (1) {/* 读入命令行 */if (emit_prompt) {printf("%s", prompt);fflush(stdout);}if ((fgets(cmdline, MAXLINE, stdin) == NULL) && ferror(stdin))app_error("fgets error");if (feof(stdin)) { /* End of file (ctrl-d) */fflush(stdout);exit(0);}/* 处理命令行 */eval(cmdline);fflush(stdout);fflush(stdout);}exit(0); /* control never reaches here */}/** eval - Evaluate the command line that the user has just typed in** If the user has requested a built-in command (quit, jobs, bg or fg)* then execute it immediately. Otherwise, fork a child process and* run the job in the context of the child. If the job is running in* the foreground, wait for it to terminate and then return. Note:* each child process must have a unique process group ID so that our* background children don't receive SIGINT (SIGTSTP) from the kernel* when we type ctrl-c (ctrl-z) at the keyboard.*//** eval函数是用来处理命令行输入的主要逻辑,所有的处理执行逻辑在这里实现*/void eval(char *cmdline){/* $begin handout */char *argv[MAXARGS]; /* argv for execve() */int bg; /* should the job run in bg or fg? */pid_t pid; /* process id */sigset_t mask; /* signal mask *//*解析命令行*/bg = parseline(cmdline, argv);if (argv[0] == NULL)return; /* ignore empty lines */if (!builtin_cmd(argv)) {/* 将SIGCHLD SIGINT SIGSTP的信号阻塞 因为在这些处理程序中都是用了job相关的函数* 也就是同时调用了全局变量jobs 为了避免竞争所以对这些信号进行阻断* 同时需要注意 需要输出错误信息*/if (sigemptyset(&mask) < 0)unix_error("sigemptyset error");if (sigaddset(&mask, SIGCHLD))unix_error("sigaddset error");if (sigaddset(&mask, SIGINT))unix_error("sigaddset error");if (sigaddset(&mask, SIGTSTP))unix_error("sigaddset error");if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0)unix_error("sigprocmask error");/* 创建一个子进程 */if ((pid = fork()) < 0)unix_error("fork error");/** 子进程中的执行逻辑 用pid=0来区分*/if (pid == 0) {/* 子进程 解锁信号 */sigprocmask(SIG_UNBLOCK, &mask, NULL);/* 对每一个子进程开一个单独的进程组 用setpid(0,0)来实现 */if (setpgid(0, 0) < 0)unix_error("setpgid error");/* 执行新的程序 */if (execve(argv[0], argv, environ) < 0) {printf("%s: Command not found\n", argv[0]);exit(0);}}/** 父进程*//* 为了解决父进程与子进程之前存在的race问题,上面设置了信号的封锁,* 这里在添加了job之后需要对上面封锁的信号进行解锁*/addjob(jobs, pid, (bg == 1 ? BG : FG), cmdline);sigprocmask(SIG_UNBLOCK, &mask, NULL);if (!bg)waitfg(pid);elseprintf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);}/* $end handout */return;}/** parseline - Parse the command line and build the argv array.** Characters enclosed in single quotes are treated as a single* argument. Return true if the user has requested a BG job, false if* the user has requested a FG job.*//* 解析命令行 */int parseline(const char *cmdline, char **argv){static char array[MAXLINE]; /* holds local copy of command line */char *buf = array; /* ptr that traverses command line */char *delim; /* points to first space delimiter */int argc; /* number of args */int bg; /* background job? */strcpy(buf, cmdline);buf[strlen(buf)-1] = ' '; /* replace trailing '\n' with space */while (*buf && (*buf == ' ')) /* ignore leading spaces */buf++;/* Build the argv list */argc = 0;if (*buf == '\'') {buf++;delim = strchr(buf, '\'');}else {delim = strchr(buf, ' ');}while (delim) {argv[argc++] = buf;*delim = '\0';buf = delim + 1;while (*buf && (*buf == ' ')) /* ignore spaces */buf++;if (*buf == '\'') {buf++;delim = strchr(buf, '\'');}else {delim = strchr(buf, ' ');}}argv[argc] = NULL;if (argc == 0) /* ignore blank line */return 1;/* should the job run in the background? */if ((bg = (*argv[argc-1] == '&')) != 0) {argv[--argc] = NULL;}return bg;}/** builtin_cmd - If the user has typed a built-in command then execute* it immediately.*/int builtin_cmd(char **argv){/** 判断是否是内置函数* 如果是内置函数 则执行 返回1* 如果不是内置函数 返回0*/if(!strcmp(argv[0],"quit")){ //quit 退出tshexit(0);}if(!strcmp(argv[0],"&")){//忽略单独的&return 1;}if(!strcmp(argv[0],"bg") || (!strcmp(argv[0],"fg"))) { //fg bg任务显示,调用相应函数即可do_bgfg(argv);return 1;}if(!strcmp(argv[0],"jobs")) { //列出所有任务,调用 listjobs 即可listjobs(jobs);return 1;}return 0; /* not a builtin command */}/** do_bgfg - Execute the builtin bg and fg commands*/void do_bgfg(char **argv){/* 执行内置命令bg fg *//* $begin handout */struct job_t *jobp=NULL;/* Ignore command if no argument */if (argv[1] == NULL) {printf("%s command requires PID or %%jobid argument\n", argv[0]);return;}/* Parse the required PID or %JID arg */if (isdigit(argv[1][0])) { //开头是数字的格式pid_t pid = atoi(argv[1]); //数字转换函数 可以跳过前面的空格,转换负数if (!(jobp = getjobpid(jobs, pid))) {printf("(%d): No such process\n", pid);return;}}else if (argv[1][0] == '%') { //开头是%的格式int jid = atoi(&argv[1][1]); //传入的是地址 直接取地址if (!(jobp = getjobjid(jobs, jid))) {printf("%s: No such job\n", argv[1]);return;}}else {printf("%s: argument must be a PID or %%jobid\n", argv[0]);return;}/* bg command */if (!strcmp(argv[0], "bg")) {if (kill(-(jobp->pid), SIGCONT) < 0) //向job所在的进程组发送SIGCONT信号unix_error("kill (bg) error");jobp->state = BG; //更改state为BGprintf("[%d] (%d) %s", jobp->jid, jobp->pid, jobp->cmdline);}/* fg command */else if (!strcmp(argv[0], "fg")) {if (kill(-(jobp->pid), SIGCONT) < 0) //向job所在的进程组发送SIGCONT信号unix_error("kill (fg) error");jobp->state = FG; //更改state为FGwaitfg(jobp->pid); //调用waitfg等待job,直到前台进程不是job}else {printf("do_bgfg: Internal error\n");exit(0);}/* $end handout */return;}/** waitfg - Block until process pid is no longer the foreground process*/void waitfg(pid_t pid){while(fgpid(jobs)==pid) { //busy_loop 等待前台程序不再是pidsleep(1);}}/****************** Signal handlers*****************//** sigchld_handler - The kernel sends a SIGCHLD to the shell whenever* a child job terminates (becomes a zombie), or stops because it* received a SIGSTOP or SIGTSTP signal. The handler reaps all* available zombie children, but doesn't wait for any other* currently running children to terminate.*/void sigchld_handler(int sig){/** SIGCHLD 信号处理程序*/int olderrno = errno; //记录下errno 防止在信号处理过程中 调用函数 出错 产生errno变化int status;sigset_t mask_all, prev_all;pid_t pid;sigfillset(&mask_all);while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { //while循环 回收所有僵死进程//对导致退出的情况进行屏幕回显// WHOANG|WUNTRACED 代表立即返回,如果等待集合中的子进程都没有停止或终止则返回为0,如果有一个,则返回他的PIDif (WIFEXITED(status)) { //子进程通过调用exit或者一个返回正常终止sigprocmask(SIG_BLOCK, &mask_all, &prev_all); //阻塞所有的信号deletejob(jobs, pid); //在任务列表中删除任务sigprocmask(SIG_SETMASK, &prev_all, NULL); //解除阻塞}if (WIFSTOPPED(status)) { //引起返回的子进程当前是停止的printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status));}if (WIFSIGNALED(status)) { //子进程是因为一个未被捕获的信号终止的printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status));sigprocmask(SIG_BLOCK, &mask_all, &prev_all); //在任务列表中删除任务deletejob(jobs, pid);sigprocmask(SIG_SETMASK, &prev_all, NULL);}}errno = olderrno; //恢复errno}/** sigint_handler - The kernel sends a SIGINT to the shell whenver the* user types ctrl-c at the keyboard. Catch it and send it along* to the foreground job.*/void sigint_handler(int sig){/*中断信号SIGINT处理函数*/int olderrno = errno; //保存errnopid_t pid = fgpid(jobs);if (pid == 0) {return;}kill(-pid, SIGINT); //向处于foreground正在运行的进程所处的进程组发送SIGINTerrno = olderrno;}/** sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever* the user types ctrl-z at the keyboard. Catch it and suspend the* foreground job by sending it a SIGTSTP.*/void sigtstp_handler(int sig) {// puts("handle sigstop");/*SIGSTP信号的处理函数*/pid_t pid = fgpid(jobs);if(pid == 0) return ;getjobpid(jobs, pid)->state = ST; //设置state为ST// Job [2] (29481) stopped by signal 20kill(-pid,SIGTSTP);printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, sig);return;}/********************** End signal handlers*********************//************************************************ Helper routines that manipulate the job list**********************************************//* clearjob - Clear the entries in a job struct */void clearjob(struct job_t *job) {job->pid = 0;job->jid = 0;job->state = UNDEF;job->cmdline[0] = '\0';}/* initjobs - Initialize the job list */void initjobs(struct job_t *jobs) {int i;for (i = 0; i < MAXJOBS; i++)clearjob(&jobs[i]);}/* maxjid - Returns largest allocated job ID */int maxjid(struct job_t *jobs){int i, max=0;for (i = 0; i < MAXJOBS; i++)if (jobs[i].jid > max)max = jobs[i].jid;return max;}/* addjob - Add a job to the job list */int addjob(struct job_t *jobs, pid_t pid, int state, char *cmdline){int i;if (pid < 1)return 0;for (i = 0; i < MAXJOBS; i++) {if (jobs[i].pid == 0) {jobs[i].pid = pid;jobs[i].state = state;jobs[i].jid = nextjid++;if (nextjid > MAXJOBS)nextjid = 1;strcpy(jobs[i].cmdline, cmdline);if(verbose){printf("Added job [%d] %d %s\n", jobs[i].jid, jobs[i].pid, jobs[i].cmdline);}return 1;}}printf("Tried to create too many jobs\n");return 0;}/* deletejob - Delete a job whose PID=pid from the job list */int deletejob(struct job_t *jobs, pid_t pid){int i;if (pid < 1)return 0;for (i = 0; i < MAXJOBS; i++) {if (jobs[i].pid == pid) {clearjob(&jobs[i]);nextjid = maxjid(jobs)+1;return 1;}}return 0;}/* fgpid - Return PID of current foreground job, 0 if no such job */pid_t fgpid(struct job_t *jobs) {int i;for (i = 0; i < MAXJOBS; i++)if (jobs[i].state == FG)return jobs[i].pid;return 0;}/* getjobpid - Find a job (by PID) on the job list */struct job_t *getjobpid(struct job_t *jobs, pid_t pid) {int i;if (pid < 1)return NULL;for (i = 0; i < MAXJOBS; i++)if (jobs[i].pid == pid)return &jobs[i];return NULL;}/* getjobjid - Find a job (by JID) on the job list */struct job_t *getjobjid(struct job_t *jobs, int jid){int i;if (jid < 1)return NULL;for (i = 0; i < MAXJOBS; i++)if (jobs[i].jid == jid)return &jobs[i];return NULL;}/* pid2jid - Map process ID to job ID */int pid2jid(pid_t pid){int i;if (pid < 1)return 0;for (i = 0; i < MAXJOBS; i++)if (jobs[i].pid == pid) {return jobs[i].jid;}return 0;}/* listjobs - Print the job list */void listjobs(struct job_t *jobs){int i;for (i = 0; i < MAXJOBS; i++) {if (jobs[i].pid != 0) {printf("[%d] (%d) ", jobs[i].jid, jobs[i].pid);switch (jobs[i].state) {case BG:printf("Running ");break;case FG:printf("Foreground ");break;case ST:printf("Stopped ");break;default:printf("listjobs: Internal error: job[%d].state=%d ",i, jobs[i].state);}printf("%s", jobs[i].cmdline);}}}/******************************* end job list helper routines******************************//************************ Other helper routines***********************//** usage - print a help message*/void usage(void){printf("Usage: shell [-hvp]\n");printf(" -h print this message\n");printf(" -v print additional diagnostic information\n");printf(" -p do not emit a command prompt\n");exit(1);}/** unix_error - unix-style error routine*/void unix_error(char *msg){fprintf(stdout, "%s: %s\n", msg, strerror(errno));exit(1);}/** app_error - application-style error routine*/void app_error(char *msg){fprintf(stdout, "%s\n", msg);exit(1);}/** Signal - wrapper for the sigaction function*//* 给出的通过sigaction进行的包装 完成信号注册的功能 */handler_t *Signal(int signum, handler_t *handler){struct sigaction action, old_action;action.sa_handler = handler;sigemptyset(&action.sa_mask); /* block sigs of type being handled */action.sa_flags = SA_RESTART; /* restart syscalls if possible */if (sigaction(signum, &action, &old_action) < 0)unix_error("Signal error");return (old_action.sa_handler);}/** sigquit_handler - The driver program can gracefully terminate the* child shell by sending it a SIGQUIT signal.*/void sigquit_handler(int sig){printf("Terminating after receipt of SIGQUIT signal\n");exit(1);}
第4章 TinyShell测试
4.1 测试方法
4.2 测试结果评价
(2)测试文件trace11.txt, trace12.txt和trace13.txt中的/bin/ps命令,每次运行的输出都会不同,但每个mysplit进程的运行状态应该相同。
除了上述两方面允许的差异,tsh与tshref的输出相同则判为正确,如不同则给出原因分析。
4.3 自测试结果
4.3.1测试用例trace01.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.2测试用例trace02.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.3测试用例trace03.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.4测试用例trace04.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.5测试用例trace05.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.6测试用例trace06.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.7测试用例trace07.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.8测试用例trace08.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.9测试用例trace09.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.10测试用例trace10.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.11测试用例trace11.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.12测试用例trace12.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
|
4.3.13测试用例trace13.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.14测试用例trace14.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.3.15测试用例trace15.txt的输出截图(1分)
tsh测试结果 |
tshref测试结果 |
|
测试结论 |
相同 |
4.4 自测试评分
第4章 总结
4.1 请总结本次实验的收获
4.2 请给出对本次实验内容的建议
参考文献
[1] 林来兴. 空间控制技术[M]. 北京:中国宇航出版社,1992:25-42.
[2] 辛希孟. 信息技术与信息服务国际研讨会论文集:A集[C]. 北京:中国科学出版社,1999.
[4] 谌颖. 空间交会控制理论与方法研究[D]. 哈尔滨:哈尔滨工业大学,1992:8-13.
[5] KANAMORI H. Shaking Without Quaking[J]. Science,1998,279(5359):2063-2064.
哈工大计算机系统实验七——微壳相关推荐
- 哈工大计算机系统实验二——DataLab数据表示
计算机系统实验二特别难,和上一届的实验不一样,没有学长的火炬,当时做的时候特别崩溃.幸好有一帮志同道合的伙伴们,一起慢慢把实验解决了. 把火炬传下去! 实验报告 实 验(二) 题 目 Data ...
- 哈工大计算机系统实验一:计算机系统漫游
计算机系统实验一:计算机系统漫游 寒假直接copy文档上传,有错误很正常(有对不上的地方请私聊我改正一下) 把火炬传下去把! 实验报告 实 验(一) 题 目 计算机系统漫游 专 业 ...
- 哈工大计算机系统实验六——高速缓冲器模拟
实验报告 实 验(六) 题 目 Cachelab 高速缓冲器模拟 专 业 xxxx 学 号 xxxx 班 级 xxxx 学 生 xxxx 指 导 教 师 x ...
- 哈工大计算机系统实验四——链接
链接这一块呢,先看了李春凤老师的慕课,然后看一遍课本,然后来做实验,感觉真的懂了一样 把火炬传下去! 实验报告 实 验(四 题 目 LinkLab 链接 专 业 xxxx 学 ...
- 哈工大计算机系统lab7——微壳
实验报告 实 验(七) 题 目 TinyShell 微壳 专 业 计算机类 学 号 ********** 班 级 1903003 学 生 李*涵 ...
- 计算机组成实验脱机,计算机组成原理 实验七 脱机方式下微代码装入与执行实验.doc...
计算机组成原理 实验七 脱机方式下微代码装入与执行实验 实验七 脱机方式下微代码装入与执行实验 一.实验目的 通过微程序的编制.装入.执行,验证微程序控制的工作方法. 观察微程序的运行过程,未进行简单 ...
- 计算机组成原理微代码的修改,计算机组成原理实验七脱机方式下微代码装入与执行实验...
<计算机组成原理实验七脱机方式下微代码装入与执行实验>由会员分享,可在线阅读,更多相关<计算机组成原理实验七脱机方式下微代码装入与执行实验(6页珍藏版)>请在人人文库网上搜索. ...
- 计算机组成原理微代码的修改,计算机组成原理实验七脱机方式下微代码装入与执行实验.doc...
文档介绍: 计算机组成原理--实验七--脱机方式下微代码装入与执行实验--------------------------------作者:------------------------------ ...
- 操作系统实验七 地址映射与共享(哈工大李治军)
实验七 地址映射与共享 实验目的 深入理解操作系统的段.页式内存管理,深入理解段表.页表.逻辑地址.线性地址.物理地址等概念: 实践段.页式内存管理的地址映射过程: 编程实现段.页式内存管理上的内存共 ...
最新文章
- java循环队列_java实现循环队列(顺序队列)
- php函数表达式,正规表达式函数_php
- c语言 函数的参数传递示例_C语言中带有示例的remove()函数
- API的非向后兼容性无论如何通常代表着一种比较差的设计
- 【SpringMVC框架】springmvc的基础知识
- mysql 的标识符_MySQL查询或标识符在Jupyter中太长?
- Tab与TabHost
- springboot启动命令linux,springboot项目命linux环境下命令启动
- Android Sensor传感器系统架构初探
- 浅析如何让Spring 来管理Action的配置方法
- php单列模式_PHP单例模式详解及实例代码
- Qt_ERROR qt闪退 竟然是因为pro文件中的冒出来的\n
- 所谓厉害的人,遇到问题时的思维模式与我们的差别在哪?(转自知乎)
- 找到某个关键字 同义词词林 python_读一读我——无废话Python(三)条件、循环、函数、表达式
- 计算机二级excel常见函数函数多表求和,excel sumif函数多条件求和 sumif的高级用法:跨多表条件求和...
- 网页title如何优化
- Tomcat日志切割工具 logrotate
- 机器人设计的步骤有哪些
- html 的页眉页脚,html – 带滚动条的页眉,页脚和内容的CSS布局
- java 房贷计算器代码_用JAVA编程一个房贷计算器