文章目录

  • Lab 总结博客链接
  • 前引
  • Lab5 Shell Lab
    • 1、获取相关Lab材料
    • 2、Overview(总览)
    • 3、Explore(实现前的摸索)
    • 4、函数实现 + 实现代码分析
      • 1、eval(解析函数 约75行)
      • 2、builtin_cmd(内置命令 约25行)
      • 3、sigchld handler (子进程回收处理 约80行)
      • 4、do_bgfg(内置命令 FG BG重启任务 约50行)
      • 5、sigint_handler(ctrl+c SIGINT结束 信号处理函数 约15行)
      • 6、sigtstp_handler(ctrl+z SIGTSTP信号处理函数 约15行)
    • 5、最终代码实现(tsh.c)
    • 6、make rtest 验证代码
  • 结束语

Lab 总结博客链接


CSAPP Lab入门系统安装摸索 + Lab 博客链接


前引


这两天啥都没干 在寝室的床上坐着 把这个Lab给完成了 - -
主要是重庆这个天气 我又起不来床 外面又冷 这段时间又有点懒呜

好了好了 不扯那么多有的没的了 待会还要抄大物实验报告 博客还是好好写吧 毕竟在床上躺着 是花了两天 (maybe 一天多一点的时间)

那我们下面走起吧


Lab5 Shell Lab


1、获取相关Lab材料


老样子 给一下官网的下载链接吧 我们直接下载下来 解压即可
CSAPP 配套Lab下载 Self-Study Handout

然后我们再下一下Write Up 下面是实验文档截图 我用wps中文翻译了一下 比较好浏览大意 但还是需要看英文pdf


2、Overview(总览)


这部分Overview 是我写出来说一下这个Lab我们需要干什么 在完成这个Lab前我强烈建议认真的读完第八章(异常控制流)的内容 因为我就是没有认真看完 然后就开始做 做到中间发现有些地方卡住了 出现了问题 后面才发现书中写了怎么解决 然后还介绍了大量要完成这个Lab必须要用的函数 所以强烈大家认真读完第八章再来做 会简单很多


这一个Lab 主要就是让我们完成一个简单的shell 实现功能如下

eval 解析和解释命令行的主要例程。[70行]
builtin_cmd :识别和解释内置命令:退出、FG、BG和jobs.line] [25行]
do_bgfg :实现bgandfg内置命令。[50行]
waitfg:等待前台工作完成。[20行]
sigchld handler:捕获SIG_CHILD信号。[80行]
sigint handler:捕获SIG_INT(ctrl-c)信号。[15行]
sigtstp handler:捕获SIGTSTP(ctrl-z)信号…[15行]


3、Explore(实现前的摸索)


现在感觉有点模模糊糊的 无所谓 因为我们有示例程序可以参照 很多行为 比如我们想看看./myspin 20 &后台停顿20秒 然后看看jobs示例出所有目前的工作 看看示例程序怎么做的 我们就输入

./tshref(示例程序)
./myspin 20 &(后台程序启动 20s '&'指的是后台)
jobs(列出目前所有状态的程序)


我们可以看一下下面的输出 输入启动一个后台程序后 输出了子进程的pid 还有jid (在tsh.c中定义) 还有我们的输入的命令
对于jobs 列出了我们所有的示例程序

我们可以就按照这样的思路 和调试 去试我们程序的反馈 还有应该出现的行文 我们就可以按照下面的示例程序输出 来做我们的程序


相关的测试文件为Trace 01 - Trace 16 我们可以点开 看看 有哪些输入 如果需要测试时 我们可以按照make test03来用我们的程序测试trace03是否行为正确 如果看示例程序的输出的话 make rtest03来输出 下面是我的测试截图 测试trace 15-16的截图 如果行为除了pid以外是相同的话 即这个trace测试正确 一共有16个trace 我们可以一个一个来测试 来推进程序编写


4、函数实现 + 实现代码分析


1、eval(解析函数 约75行)


eval-评估用户刚刚键入的命令行
如果用户已请求内置命令(退出、作业、bg或fg)然后立即执行它。否则,派生一个子进程并在子对象的上下文中运行作业。如果作业正在运行前台,等待它终止,然后返回。注:每个子进程必须具有唯一的进程组ID,以便后台子级不从内核接收SIGINT(SIGTSTP) 当我们在键盘上键入ctrl-c(ctrl-z)时。(机翻)

这个函数要不停的循环在循环体内 解析命令行 我们通过已经给的parseline函数来解析成一个一个字符指针 如果发现是内置 则直接进行内置命令即可 详细看


eval代码实现

void eval(char *cmdline)
{char* argv[MAXARGS] = {NULL};int FG_BG = parseline(cmdline,argv) + 1;if(argv[0] == NULL)    return;if(!builtin_cmd(argv)) //如果是内置命令 直接进入 不再进入{sigset_t mask_all,mask_one,prev_one;//信号集合sigfillset(&mask_all);sigemptyset(&mask_one);sigemptyset(&prev_one);sigaddset(&mask_one,SIGCHLD);pid_t fpid;sigprocmask(SIG_BLOCK,&mask_one,&prev_one); //防止子进程先被调度//让add先于deletefpid = fork();if(!fpid) {setpgid(0, 0);             //子进程另进进程组//防止int ctrl+c 传给shell进程 sigprocmask(SIG_SETMASK,&prev_one,NULL); //解开信号量阻塞if(execve(argv[0],argv,environ) == -1){printf("%s: Command not found\n",argv[0]);exit(0);}}else{sigprocmask(SIG_BLOCK,&mask_all,NULL); //全屏蔽 全局变量addjob(jobs,fpid,FG_BG,cmdline);sigprocmask(SIG_SETMASK,&mask_one,NULL); //恢复if(FG_BG == FG)  waitfg(fpid); //FG 前台else{sigprocmask(SIG_SETMASK,&mask_all,NULL); //pid2jid 访问呢全局变量int insert_jid = pid2jid(fpid);if(FG_BG == BG)    printf("[%d] (%d) %s",insert_jid,fpid,cmdline); //后台运行 则输出}} sigprocmask(SIG_SETMASK,&prev_one,NULL); //全解} return;
}

2、builtin_cmd(内置命令 约25行)


这个就是针对下面四条命令

jobs 列出所有状态的任务(除已经结束了 暂停的也要列)
bg <jid/pid> 使一个后台任务(暂停或者正在运行) 重新后台启动
fg <jid/pid> 使一个任务 重新运行 并前台运行
quit 直接退出程序


builtin_cmd代码实现

int builtin_cmd(char **argv)
{if(!strcmp(argv[0],"quit"))    exit(0); //如果是quit 直接退出bool func_jobs = !(strcmp(argv[0],"jobs"));bool func_fg   = !(strcmp(argv[0],"fg"));bool func_bg   = !(strcmp(argv[0],"bg"));if(!func_jobs && !func_fg && !func_bg)   return 0; /* not a builtin command */ //如果不是内置命令中的 则返回0 表示不是内置命令 则进入eval下面的处理if(func_jobs)          listjobs(jobs); //程序已经给出了listjobs 不用担心else if(func_fg || func_bg)   do_bgfg(argv); return 1; //表示是内置命令
}

3、sigchld handler (子进程回收处理 约80行)


这里书上讲的还是很好的 很多地方都是借鉴了书上编写的思想
主要还需要处理 终端没有接受到信号的进程信号 例如trace 16


sigchld handler代码实现

void sigchld_handler(int sig)
{int olderrno = errno,status;pid_t pid;sigset_t mask_all,prev_all;sigemptyset(&prev_all);sigfillset(&mask_all);//尽可能回收僵死进程 但是如果没有停止或终结的进程 直接离开即可//trace 05 进程不止只有命令 还有/bin/echo 等进程//如果设置为0的话 则会一直等待 while((pid = waitpid(-1,&status,WNOHANG | WUNTRACED)) > 0){//全屏蔽 有deletesigprocmask(SIG_BLOCK,&mask_all,&prev_all);struct job_t* job = getjobpid(jobs,pid);if(WIFSIGNALED(status) && WTERMSIG(status) == SIGINT && job->state != UNDEF) //外部SIGINT 处理printf("Job [%d] (%d) terminated by signal 2\n",job->jid,job->pid); //外部SIGTSTP 处理else if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTSTP && job->state != ST){printf("Job [%d] (%d) terminated by signal 20\n",job->jid,job->pid);job->state = ST; //处理为STOP }if(getjobpid(jobs,pid)->state != ST) deletejob(jobs,pid); //如果是STOP 则先不删除 如果后面还有 BG FG 仍可重新用sigprocmask(SIG_SETMASK,&prev_all,NULL);}                     errno = olderrno;return;
}

4、do_bgfg(内置命令 FG BG重启任务 约50行)


do_bgfg 重启任务 注意输出要求 没什么好讲的 - -


do_bgfg代码实现

void do_bgfg(char **argv)
{int bg_fg = (!strcmp(argv[0],"bg")) + 1; bool argv1_read = (argv[1] != NULL);if(!argv1_read){printf("%s command requires PID or %%jobid argument\n",argv[0]);return;}bool pid_read = (argv[1] && argv[1][0] >= '0' && argv[1][0] <= '9');bool jid_read = (argv[1] && argv[1][0] == '%');if(!pid_read && !jid_read){printf("%s: argument must be a PID or %%jobid\n",argv[0]);return;}struct job_t* job_ptr = NULL;if(pid_read)    job_ptr = getjobpid(jobs,atoi(argv[1]));else       job_ptr = getjobjid(jobs,atoi(argv[1]+1));if(!job_ptr){if(pid_read)   printf("(%d): No such process\n",atoi(argv[1]));else          printf("%s: No such job\n",argv[1]);return;}job_ptr->state = bg_fg; //重新设置状态kill(-job_ptr->pid,SIGCONT); //发送状态 重启if(bg_fg == BG) printf("[%d] (%d) %s",job_ptr->jid,job_ptr->pid,job_ptr->cmdline);if(bg_fg == FG)waitfg(job_ptr->pid); return;
}

5、sigint_handler(ctrl+c SIGINT结束 信号处理函数 约15行)


这里的话 也没什么好说的 大家看代码的注释吧


sigchld_handler代码实现

void sigint_handler(int sig)
{int fg_pid = fgpid(jobs),fg_jid = pid2jid(fg_pid);if(!fg_pid)    return;sigset_t mask_all,prev_all;sigfillset(&mask_all);sigemptyset(&prev_all);sigprocmask(SIG_BLOCK,&mask_all,&prev_all);struct job_t* job = getjobpid(jobs,fg_pid);job->state = UNDEF;kill(-fg_pid,2);printf("Job [%d] (%d) terminated by signal 2\n",fg_jid,fg_pid);sigprocmask(SIG_SETMASK,&prev_all,NULL);return;
}

6、sigtstp_handler(ctrl+z SIGTSTP信号处理函数 约15行)


这个和上面大同小异 一点点区别 大家看代码就好


sigtstp_handler代码实现

void sigtstp_handler(int sig)
{int fg_pid = fgpid(jobs),fg_jid = pid2jid(fg_pid);if(!fg_pid)    return;sigset_t mask_all,prev_all;sigfillset(&mask_all);sigemptyset(&prev_all);sigprocmask(SIG_BLOCK,&mask_all,&prev_all);struct job_t* job = getjobpid(jobs,fg_pid);job->state = ST;kill(-fg_pid,20);printf("Job [%d] (%d) stopped by signal 20\n",fg_jid,fg_pid);sigprocmask(SIG_SETMASK,&prev_all,NULL);
}

5、最终代码实现(tsh.c)


下面方便大家参照 就直接放代码了
对于waitfg部分 其实是可以不用stop的 建议用sigsuspend 但我比较懒 - -后面发现还要改一些其他部分 就算了 没改了

下面就是最终代码实现啦

/* * tsh - A tiny shell program with job control* * <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 */typedef short bool;
/* bool define */
#define false 0
#define true 1/* * 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 */
int main(int argc, char **argv)
{char c;char cmdline[MAXLINE];int emit_prompt = 1; /* emit prompt (default) *//* Redirect stderr to stdout (so that driver will get all output* on the pipe connected to stdout) */dup2(1, 2);/* Parse the command line */while ((c = getopt(argc, argv, "hvp")) != EOF) {switch (c) {case 'h':             /* print help message */usage();break;case 'v':             /* emit additional diagnostic info */verbose = 1;break;case 'p':             /* don't print a prompt */emit_prompt = 0;  /* handy for automatic testing */break;default:usage();}}/* Install the signal handlers *//* These are the ones you will need to implement */Signal(SIGINT,  sigint_handler);   /* ctrl-c */Signal(SIGTSTP, sigtstp_handler);  /* ctrl-z */Signal(SIGCHLD, sigchld_handler);  /* Terminated or stopped child *//* This one provides a clean way to kill the shell */Signal(SIGQUIT, sigquit_handler); /* Initialize the job list */initjobs(jobs);/* Execute the shell's read/eval loop */while (1) {/* Read command line */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);}/* Evaluate the command line */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.
*/
void eval(char *cmdline)
{char* argv[MAXARGS] = {NULL};int FG_BG = parseline(cmdline,argv) + 1;if(argv[0] == NULL)    return;if(!builtin_cmd(argv)){sigset_t mask_all,mask_one,prev_one;sigfillset(&mask_all);sigemptyset(&mask_one);sigemptyset(&prev_one);sigaddset(&mask_one,SIGCHLD);pid_t fpid;sigprocmask(SIG_BLOCK,&mask_one,&prev_one);fpid = fork();if(!fpid) {setpgid(0, 0);sigprocmask(SIG_SETMASK,&prev_one,NULL);if(execve(argv[0],argv,environ) == -1){printf("%s: Command not found\n",argv[0]);exit(0);}}else{sigprocmask(SIG_BLOCK,&mask_all,NULL);addjob(jobs,fpid,FG_BG,cmdline);sigprocmask(SIG_SETMASK,&mask_one,NULL);if(FG_BG == FG)  waitfg(fpid);else{sigprocmask(SIG_SETMASK,&mask_all,NULL);int insert_jid = pid2jid(fpid);if(FG_BG == BG) printf("[%d] (%d) %s",insert_jid,fpid,cmdline);}} sigprocmask(SIG_SETMASK,&prev_one,NULL);} 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)
{if(!strcmp(argv[0],"quit"))    exit(0);bool func_jobs = !(strcmp(argv[0],"jobs"));bool func_fg   = !(strcmp(argv[0],"fg"));bool func_bg   = !(strcmp(argv[0],"bg"));if(!func_jobs && !func_fg && !func_bg)  return 0; /* not a builtin command */if(func_jobs)          listjobs(jobs);else if(func_fg || func_bg)  do_bgfg(argv);return 1;
}/* * do_bgfg - Execute the builtin bg and fg commands*/
void do_bgfg(char **argv)
{int bg_fg = (!strcmp(argv[0],"bg")) + 1; bool argv1_read = (argv[1] != NULL);if(!argv1_read){printf("%s command requires PID or %%jobid argument\n",argv[0]);return;}bool pid_read = (argv[1] && argv[1][0] >= '0' && argv[1][0] <= '9');bool jid_read = (argv[1] && argv[1][0] == '%');if(!pid_read && !jid_read){printf("%s: argument must be a PID or %%jobid\n",argv[0]);return;}struct job_t* job_ptr = NULL;if(pid_read)    job_ptr = getjobpid(jobs,atoi(argv[1]));else       job_ptr = getjobjid(jobs,atoi(argv[1]+1));if(!job_ptr){if(pid_read)   printf("(%d): No such process\n",atoi(argv[1]));else          printf("%s: No such job\n",argv[1]);return;}job_ptr->state = bg_fg;kill(-job_ptr->pid,SIGCONT);if(bg_fg == BG) printf("[%d] (%d) %s",job_ptr->jid,job_ptr->pid,job_ptr->cmdline);if(bg_fg == FG)waitfg(job_ptr->pid);return;
}/* * waitfg - Block until process pid is no longer the foreground process*/
void waitfg(pid_t pid)
{sigset_t mask_none,prev_all;sigemptyset(&mask_none);while(1){sigprocmask(SIG_SETMASK,&mask_none,&prev_all);int ret = fgpid(jobs);if(!ret) break;sleep(1);sigprocmask(SIG_SETMASK,&prev_all,NULL);}return;
}/****************** 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)
{int olderrno = errno,status;pid_t pid;sigset_t mask_all,prev_all;sigemptyset(&prev_all);sigfillset(&mask_all);while((pid = waitpid(-1,&status,WNOHANG | WUNTRACED)) > 0){sigprocmask(SIG_BLOCK,&mask_all,&prev_all);struct job_t* job = getjobpid(jobs,pid);if(WIFSIGNALED(status) && WTERMSIG(status) == SIGINT && job->state != UNDEF)printf("Job [%d] (%d) terminated by signal 2\n",job->jid,job->pid);else if(WIFSTOPPED(status) && WSTOPSIG(status) == SIGTSTP && job->state != ST){printf("Job [%d] (%d) terminated by signal 20\n",job->jid,job->pid);job->state = ST;}if(getjobpid(jobs,pid)->state != ST) deletejob(jobs,pid); sigprocmask(SIG_SETMASK,&prev_all,NULL);}                     errno = olderrno;return;
}/* * 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)
{int fg_pid = fgpid(jobs),fg_jid = pid2jid(fg_pid);if(!fg_pid)    return;sigset_t mask_all,prev_all;sigfillset(&mask_all);sigemptyset(&prev_all);sigprocmask(SIG_BLOCK,&mask_all,&prev_all);struct job_t* job = getjobpid(jobs,fg_pid);job->state = UNDEF;kill(-fg_pid,2);printf("Job [%d] (%d) terminated by signal 2\n",fg_jid,fg_pid);sigprocmask(SIG_SETMASK,&prev_all,NULL);return;
}/** 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)
{int fg_pid = fgpid(jobs),fg_jid = pid2jid(fg_pid);if(!fg_pid)    return;sigset_t mask_all,prev_all;sigfillset(&mask_all);sigemptyset(&prev_all);sigprocmask(SIG_BLOCK,&mask_all,&prev_all);struct job_t* job = getjobpid(jobs,fg_pid);job->state = ST;kill(-fg_pid,20);printf("Job [%d] (%d) stopped by signal 20\n",fg_jid,fg_pid);sigprocmask(SIG_SETMASK,&prev_all,NULL);
}/********************** 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*/
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);
}

6、make rtest 验证代码


下面这篇博客就是 我验证这个Shell Lab的代码正确性的博客啦
因为有16个Phase 所以图片很多 所以就单独发了一篇 大家感兴趣就点进去看一下吧 总体来说 应该是没有什么问题的 ^^
CSAPP Lab5实验记录 ---- Shell Lab(trace 16 验证博客)



结束语


这个Lab 加上编辑博客 大概写了有两天 有效时间肯定没有那么多 毕竟一直躺在床上写的呜 这段时间太懒了 人比较疲倦 而且天气冷 之后要多出门了
现在已经11:17了 大物实验还没有写 作业明天就要交了 待会还得洗澡呜 那我跑了ε=ε=ε=(~ ̄▽ ̄) ~ IT人也是需要休息的

有缘下篇博客再见啦^^

CSAPP Lab5实验记录 ---- Shell Lab(实验分析 + 完整代码)相关推荐

  1. CSAPP Lab2 实验记录 ---- Bomb Lab(Phase 1 - Phase 6详细解答 + Secret Phase彩蛋解析)

    文章目录 Lab 总结博客链接 实验前提引子 实验需要指令及准备 Phase 1 Phase 2 Phase 3 Phase 4 Phase 5 Phase 6 Phase Secret(彩蛋Phas ...

  2. CSAPP实验二——bomb lab实验

    CSAPP实验二-- bomb lab实验 实验前准备 第一部分(phase_1) 第二部分(phase_2) 第三部分(phase_3) 第四部分(phase_4) 第五部分(phase_5) 第六 ...

  3. linux 程序实验总结,Linux实验报告(实验四) shell编程实验

    实验四 shell编程实验(二) 班级:姓名:学号:上机时间:年月日 任课教师:实验教师:实验成绩: 一.实验目的 综合Linux常用命令和vi编辑器的使用,熟练掌握shell脚本编程. 二.实验注意 ...

  4. 2022华数杯B题论文思路分析+完整代码(水下机器人组装计划)(一二问答案接出来和标准答案一样)(问题三四逼近正确答案)(完整论文,代码可直接跑)

    写在前面:学校最近搞数学建模竞赛培训,以2022华数杯B题作为训练题目,在查资料过程中发现网上没有哪一篇论文解出了正确答案,而我们组利用Lingo软件准确的解出了正确答案,但是在第三问时,由于决策的变 ...

  5. 基于机器学习的上证指数、东方股吧的股市评论情感分析 完整代码数据

    视频讲解:基于机器学习的上证指数.东方股吧的股市评论情感分析 完整代码数_哔哩哔哩_bilibili 所使用模型LinearSVC,LogisticReg,SGD,MultinomialNB,KNN, ...

  6. 电子实验记录和纸质实验记录——怎么选,可以提高10倍效率

    上海鹰谷自2017年推出了电子试验记录本-InELN, 因其兼具管理和使用便利等优点和本土化的服务,得到用户的好评. 一款优秀产品的研发是没有终点的,鹰谷积极关注和持续倾听用户的意见,不断提升产品体验 ...

  7. C语言项目 电话查询系统 哈希表实现(项目要求 + 运行界面 + 代码分析 + 完整代码)

    电话查询系统 1. 项目要求 2. 数据样例 3. 运行界面 4. 代码分析 5. 完整代码 6. 项目报告 关注博主不迷路,博主带你码代码! 1. 项目要求 设每个记录有以下数据项:用户名.电话.地 ...

  8. 【2023年电工杯数学建模竞赛B题人工智能对大学生学习影响的评价】完整思路分析+完整代码

    1.问题背景与描述 这道题整体还是相对简单的,比较适合新手,选的人多对应获奖数量也会多,所以不要纠结于选题,就选你看上去能做的就好 2.问题分析 2.1 问题一的分析 对附件2中所给数据进行分析和数值 ...

  9. 基于Python实现的论坛帖子文本情感分析完整代码+数据 可直接运行 毕业设计

    完整代码:https://download.csdn.net/download/qq_38735017/87425721 一.课程项目 文本分类分析 二.项目类容 爬取川大匿名社区SCUinfo在一段 ...

最新文章

  1. java培训有哪些收费标准
  2. 强大的Mockito测试框架(转)
  3. mybatis-批量插入
  4. ES6箭头函数(Arrow Functions)
  5. MySQL 面试,必须掌握的 8 大核心点
  6. 上市即巅峰!走乐视老路的暴风 实控人冯鑫是下一个贾跃亭?
  7. 数据结构-栈(先进后出表)
  8. What day is that day? 模拟
  9. 极点五笔linux,Ubuntu 11.10安装极点五笔
  10. 最齐全的日用电商设计模板素材,速来收藏
  11. java程序员专业技能_java程序员简历专业技能怎么写
  12. CAD中怎么配置灭火器?
  13. WordPress主题制作全过程(一):基础准备
  14. 关于照片(img)的水平居中和垂直居中
  15. 芯片解密LPC2119单片机基本特性
  16. 暴雪即将公布《暗黑破坏神3》新职业
  17. vue3+element-plus动态设置字体大小
  18. ChatGPT账号注册,中国手机号为什么不行?
  19. 西门子PLC1200/1500配方实例程序
  20. android 页面默认不弹软键盘_Android 软键盘的全面解析,让你不再怕控件被遮盖!...

热门文章

  1. 供应链金融操作过程中难点解析
  2. mysql.zip版本的安装教程及环境配置
  3. Django—购物网站制作
  4. java集合之List线程安全性比较总结
  5. python 文件操作常用轮子
  6. 【渗透测试】ew代理三层靶机穿透+proxifier配置规则
  7. boston数据集预测房价
  8. js判断输入是否含有空格
  9. iPad新5.0笔刷
  10. catia 创成钣金设计_CATIA V5R20钣金设计教程