[施工完成] CSAPP shell lab
背景
动手实现一个简单的Lab,主要依赖于课本第八章的内容 感觉主要是05比较难。。发现执行的顺序不太对。。原因是SIGCHLD里面waitpid参数没写对。。 后面的就相对简单了 累计大概花了10个小时的样子
实现细节
built-in comamnd
built-in command 指的是shell自身的命令,因此只有少数几个,比如pwd.在上使用which pwd的时候,会提示"pwd: shell built-in command"
测试文件的构成
以trace04.txt举例
1#
2# trace04.txt - Run a background job.
3#
4/bin/echo -e tsh> ./myspin 1 \046
5./myspin 1 &
这是两条测试命令。。第一条是调用了 "/bin/echo -e"来执行,而且这条命令是一个fg job, \046 是'&'的ascii,这是输出字符串的一部分。
子进程中的log打印不正确
有些执行路径的log没有打印出来 可以调用flush(stdout) 确保打印
在执行fg job的时候,会等待上一个未结束的bg job执行
这是因为waitpid中的option写了默认的0,没有传入正确的option导致的
SIGCHLD的实现
感觉这个函数是整个Lab的难点
注意这里除了要对正常结束的process处理以外,也要处理因为其他原因导致的进程退出 可以根据下图的内容来判断是因为哪种原因进程结束的 这段调了好久。。虽然书上已经讲了比较多的情况。。。不过还是觉得略难
1void sigchld_handler(int sig) {
2 int olderrno = errno;
3 sigset_t mask_all, prev_all;
4 pid_t pid;
5 int status;
6 Sigfillset(&mask_all);
7
8 while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
9 if (WIFEXITED(status)) {
10 Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
11 deletejob(jobs, pid);
12 Sigprocmask(SIG_SETMASK, &prev_all, NULL);
13 } else if (WIFSIGNALED(status)) {
14 printf("Job (%d) [%d] terminated by signal %d\n",
15 pid2jid(pid), pid, WTERMSIG(status));
16 Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
17
18 deletejob(jobs, pid);
19 Sigprocmask(SIG_SETMASK, &prev_all, NULL);
20 } else if (WIFSTOPPED(status)) {
21 printf("Job (%d) [%d] stopped by signal %d\n",
22 pid2jid(pid), pid, WSTOPSIG(status));
23 struct job_t* job = getjobpid(jobs, pid);
24 if (job != NULL) {
25 job->state = ST;
26 }
27 }
28 }
29 errno = olderrno;
30}
31
do_bgfg
一开始可能会有些纠结。。怎么转换bg和fg呢。。 实际上直接改变state就好了 所谓bg job还是 fg job,其实区别就在于当前process要不要等其结束。。并没有什么本质区别
1void do_bgfg(char** argv) {
2 char* cmd = argv[0];
3 char* id = argv[1];
4 if (id == NULL) {
5 printf("%s command requires PID or %%jobid argument\n", cmd);
6 return;
7 }
8
9 struct job_t* job;
10 if (id[0] == '%') {
11 int jid = atoi(&id[1]);
12 if (jid == 0) {
13 printf("%s: argument must be a PID or %%jobid\n", cmd);
14 return;
15 }
16 job = getjobjid(jobs, jid);
17 if (job == NULL) {
18 printf("%%%d: No such job\n", jid);
19 return;
20 }
21
22 } else {
23 pid_t pid = atoi(id);
24 if (pid == 0) {
25 printf("%s: argument must be a PID or %%jobid\n", cmd);
26 return;
27 }
28 job = getjobpid(jobs, pid);
29 if (job == NULL) {
30 printf("(%d): No such process\n", pid);
31 return;
32 }
33 }
34
35 Kill(-job->pid, SIGCONT);
36 if (cmd[0] == 'b') {
37 job->state = BG;
38 printf("[%d] (%d) %s", pid2jid(job->pid), job->pid,
39 job->cmdline);
40
41 } else {
42 job->state = FG;
43 // 变为fg后,需要一直等到结束
44 waitfg(job->pid);
45 }
46}
eval
直接让写可能确实比较有难度。。好在课本以及lab的说明上给了足够多的示例代码和hint.. 所以难度其实还好
1
2void eval(char* cmdline) {
3 char* parsed_args[MAXARGS];
4 char buf[MAXLINE];
5
6 strcpy(buf, cmdline);
7 int bg = parseline(cmdline, &parsed_args[0]);
8 if (parsed_args[0] == NULL) {
9 // ignore empty lines
10 return;
11 }
12 sigset_t mask_all, mask_one, prev_one;
13 // mask_all 是屏蔽全部信号
14 // mask_one 是屏蔽SIGCHLD信号
15 Sigfillset(&mask_all);
16 Sigemptyset(&mask_one);
17 Sigaddset(&mask_one, SIGCHLD);
18
19 if (builtin_cmd(parsed_args) == 0) {
20 pid_t pid;
21 // printf("bg:%d cmdline :%s\n", bg, cmdline);
22
23 // block SIGCHLD
24 Sigprocmask(SIG_BLOCK, &mask_one, &prev_one);
25 if ((pid = Fork()) == 0) {
26 // child process
27 // printf("in child process\n");
28 Sigprocmask(SIG_SETMASK, &prev_one,
29 NULL); // unblock SIGCHLD
30 // printf("before setpgid\n");
31 setpgid(0, 0);
32 // printf("before execve\n");
33
34 // 打log记得调用fflush,不然可能还没来得及输出到屏幕上就exit了
35 fflush(stdout);
36 fflush(stdout);
37 // 现在的background是虚假的。。其实还是会等待。。
38 // 如果后面都是bg指令,就不会等待,但是如果有fg指令,就会等待。
39 Execve(parsed_args[0], parsed_args, environ);
40 }
41 // printf("pid =%d\n", pid);
42 // printf("before add job block all signals\n");
43 Sigprocmask(SIG_BLOCK, &mask_all, NULL);
44 addjob(jobs, pid, bg ? BG : FG, cmdline);
45 Sigprocmask(SIG_SETMASK, &prev_one, NULL);
46
47 // parent wait child
48 if (!bg) {
49 waitfg(pid);
50 } else {
51 printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
52 }
53 }
54 return;
55}
56
完整代码参考: 这里
Posts in this Series
- [施工完成] CSAPP shell lab
- [施工完成] CSAPP Malloc lab
- [施工完成] CSAPP Cachelab
- 【施工完成】CSAPP archlab
- 【施工完成】CSAPP attacklab
- 【施工完成】CSAPP bomb lab
- 【施工完成】CSAPP data lab