官网 http://csapp.cs.cmu.edu/3e/labs.html
Students implement simple logical, two’s complement, and floating point functions, but using a highly restricted subset of C. For example, they might be asked to compute the absolute value of a number using only bit-level operations and straightline code. This lab helps students understand the bit-level representations of C data types and the bit-level behavior of the operations on data.
参考 CSAPP实验之shell lab
实验要求和可选辅助函数见参考链接。
void eval(char *cmdline) 解析并执行命令。
void eval (char *cmdline) { char *argv[MAXARGS]; char buf[MAXLINE]; int bg; int state; pid_t pid; sigset_t mask_all, mask_one, prev; sigfillset(&mask_all); sigemptyset(&mask_one); sigaddset(&mask_one, SIGCHLD); strcpy (buf, cmdline); bg = parseline(buf, argv); if (argv[0 ] == NULL ) return ; if (!builtin_cmd(argv)) { sigprocmask(SIG_BLOCK, &mask_one, &prev); if ((pid = fork()) == 0 ) { sigprocmask(SIG_SETMASK, &prev, NULL ); if (setpgid(0 , 0 ) < 0 ) { perror("SETPGID ERROR" ); } if (execve(argv[0 ], argv, environ) < 0 ) { printf ("%s: Command not found\n" , argv[0 ]); } exit (0 ); } state = bg ? BG : FG; sigprocmask(SIG_BLOCK, &mask_all, NULL ); addjob(jobs, pid, state, cmdline); sigprocmask(SIG_SETMASK, &prev, NULL ); if (state == FG) waitfg(pid); else { sigprocmask(SIG_BLOCK, &mask_all, NULL ); printf ("[%d] (%d) %s" , pid2jid(pid), pid, cmdline); } sigprocmask(SIG_SETMASK, &prev, NULL ); } return ; }
int builtin_cmd(char **argv) 检测命令是否为内置命令quit
、fg
、bg
、jobs
。
int builtin_cmd (char **argv) { sigset_t mask_all, prev; sigfillset(&mask_all); if (!strcmp (argv[0 ], "quit" )) exit (0 ); else if (!strcmp (argv[0 ], "jobs" )) { sigprocmask(SIG_BLOCK, &mask_all, &prev); listjobs(jobs); sigprocmask(SIG_SETMASK, &prev, NULL ); return 1 ; } else if (!strcmp (argv[0 ], "bg" ) || !strcmp (argv[0 ], "fg" )) { do_bgfg(argv); return 1 ; } else if (!strcmp (argv[0 ], "&" )) return 1 ; return 0 ; }
void do_bgfg(char **argv) 实现bg
、fg
命令。
void do_bgfg (char **argv) { if (argv[1 ] == NULL ) { printf ("%s command requires PID or %%jobid argument\n" , argv[0 ]); return ; } int id; sigset_t mask_all, prev; sigfillset(&mask_all); struct job_t *job ; if (sscanf (argv[1 ], "%%%d" , &id) > 0 ) { sigprocmask(SIG_BLOCK, &mask_all, &prev); job = getjobjid(jobs, id); if (job == NULL ) { printf ("%%%d: No such job\n" , id); sigprocmask(SIG_SETMASK, &prev, NULL ); return ; } } else if (sscanf (argv[1 ], "%d" , &id) > 0 ) { sigprocmask(SIG_BLOCK, &mask_all, &prev); job = getjobpid(jobs, id); if (job == NULL ) { printf ("(%d): No such process\n" , id); sigprocmask(SIG_SETMASK, &prev, NULL ); return ; } } else { printf ("%s: argument must be a PID or %%jobid\n" , argv[0 ]); return ; } if (!strcmp (argv[0 ], "bg" )) { kill(-(job->pid), SIGCONT); job->state = BG; printf ("[%d] (%d) %s" , job->jid, job->pid, job->cmdline); } else { kill(-(job->pid), SIGCONT); job->state = FG; waitfg(job->pid); } sigprocmask(SIG_SETMASK, &prev, NULL ); return ; }
void waitfg(pid_t pid) 等待前台命令执行完成。
void waitfg (pid_t pid) { sigset_t mask_temp; sigemptyset(&mask_temp); while (fgpid(jobs) > 0 ) sigsuspend(&mask_temp); return ; }
void sigchld_handler(int sig) 处理SIGCHLD
信号,即子进程停止或终止。
void sigchld_handler (int sig) { int olderrno = errno; int status; pid_t pid; sigset_t mask_all, prev; sigfillset(&mask_all); while ((pid = waitpid(-1 , &status, WNOHANG | WUNTRACED)) > 0 ) { sigprocmask(SIG_BLOCK, &mask_all, &prev); if (WIFEXITED(status)) { deletejob(jobs, pid); } else if (WIFSIGNALED(status)) { struct job_t *job = getjobpid(jobs, pid); printf ("Job [%d] (%d) terminated by signal %d\n" , job->jid, job->pid, WTERMSIG(status)); deletejob(jobs, pid); } else { struct job_t *job = getjobpid(jobs, pid); printf ("Job [%d] (%d) stopped by signal %d\n" , job->jid, job->pid, WSTOPSIG(status)); job->state = ST; } sigprocmask(SIG_SETMASK, &prev, NULL ); } errno = olderrno; return ; }
void sigint_handler(int sig) 处理SIGINT
信号,即来自键盘的中断ctrl-c
。
void sigint_handler (int sig) { int olderrno = errno; pid_t pid; sigset_t mask_all, prev; sigfillset(&mask_all); sigprocmask(SIG_BLOCK, &mask_all, &prev); pid = fgpid(jobs); sigprocmask(SIG_SETMASK, &prev, NULL ); if (pid != 0 ) kill(-pid, sig); errno = olderrno; return ; }
void sigtstp_handler(int sig) 处理SIGTSTP
信号,即终端停止信号ctrl-z
。
void sigtstp_handler (int sig) { int olderrno = errno; pid_t pid; sigset_t mask_all, prev; sigfillset(&mask_all); sigprocmask(SIG_BLOCK, &mask_all, &prev); pid = fgpid(jobs); sigprocmask(SIG_SETMASK, &prev, NULL ); if (pid != 0 ) kill(-pid, sig); errno = olderrno; return ; }
部分测试结果