shlab
- 这个lab主要是考察
信号
的使用,还有进程创建的知识。
首先回顾一下信号处理程序的终点:
- 处理程序要尽可能简单。
- 在处理程序中只调用
异步信号安全的函数
。(可重入的且不能被信号处理程序中断)。
- 在进入处理程序时把
errno
保存在某个局部变最中,在处理程序返回前恢复它。
阻塞所有的信号
,保护对共享全局数据
结构的访问。
首先是参数解析执行,在子进程创建过程中,设置和解除阻塞的SIGCHLD
信号来避免进程在添加进job组
前终止导致把不存在的子进程添加到作业列表中,书上已经给我们例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| void eval(char *cmdline) { char *argv[MAXARGS] = {NULL}; int fg_bg; pid_t pid; sigset_t mask_all, mask_one, prev_one;
sigfillset(&mask_all); sigemptyset(&mask_one); sigaddset(&mask_one, SIGCHLD);
fg_bg = parseline(cmdline,argv) + 1; if(argv[0] == NULL) return; if(!builtin_cmd(argv)) { sigprocmask(SIG_BLOCK, &mask_one, &prev_one); if((pid=fork())==0){ sigprocmask(SIG_SETMASK, &prev_one, NULL); setpgid(0, 0); if(execve(argv[0],argv,environ)<0) { printf("%s:Command not found!",argv[0]); } exit(0); }
sigprocmask(SIG_BLOCK, &mask_all, NULL); addjob(jobs,pid,fg_bg,cmdline); sigprocmask(SIG_SETMASK, &prev_one, NULL);
if(fg_bg == FG) { waitfg(pid); } else { int jid = pid2jid(pid); printf("[%d] (%d) %s",jid , pid, cmdline); } } return; }
|
这里是判断是否为内置命令,如果是,则执行对应命令,返回1,否则返回0。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| int builtin_cmd(char **argv) { if(!strcmp(argv[0],"quit")) { exit(0); }
bool m_job = !strcmp(argv[0],"jobs"); bool m_bg = !strcmp(argv[0],"bg"); bool m_fg = !strcmp(argv[0],"fg");
if(m_job) { listjobs(jobs); return 1; } else if(m_bg || m_fg) { do_bgfg(argv); return 1; }
return 0; }
|
执行bg和fg任务,对命令行参数进行解析,执行对应操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| void do_bgfg(char **argv) { int bg_fg = (!strcmp(argv[0],"bg"))+1; struct job_t* job = NULL; int id; if(argv[1] == NULL) { printf("%s command requires PID or %%jobid argument\n",argv[0]); return ; }
if(argv[1][0]=='%'){ if(sscanf(&argv[1][1], "%d", &id) > 0){ job = getjobjid(jobs, id); if(job==NULL){ printf("%%%d: No such job\n", id); return; } } } else if(!isdigit(argv[1][0])) { printf("%s: argument must be a PID or %%jobid\n", argv[0]); return; } else{ id = atoi(argv[1]); job = getjobpid(jobs,id); if(job == NULL) { printf("%d: No such job\n", id); return; } }
kill(-(job->pid),SIGCONT);
job->state = bg_fg; if(bg_fg==BG) printf("[%d] (%d) %s",job->jid, job->pid, job->cmdline); else waitfg(job->pid); return; }
|
等待前台命令执行完成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| void waitfg(pid_t pid) { sigset_t mask_all, prev_all; sigfillset(&mask_all); sigemptyset(&prev_all); while(1) {
sigprocmask(SIG_BLOCK, &mask_all, NULL); struct job_t *fg_job = getjobpid(jobs,pid); sigprocmask(SIG_SETMASK, &prev_all, NULL);
if (!fg_job || fg_job->state != FG) break; sleep(1); }
return; }
|
下面是信号处理
处理终止的子进程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| void sigchld_handler(int sig) { int olderrno = errno; int status; sigset_t mask_all, prev_all; pid_t pid; struct job_t* job; sigfillset(&mask_all);
while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { sigprocmask(SIG_BLOCK, &mask_all, &prev_all); job = getjobpid(jobs,pid); if(WIFSTOPPED(status)) { printf("Job [%d] (%d) terminated by signal 20\n",job->jid,job->pid); job->state = ST; } else if(WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by signal 2\n",job->jid,job->pid); deletejob(jobs,pid); } else if (WIFEXITED(status)){ deletejob(jobs, pid); } sigprocmask(SIG_SETMASK, &prev_all, NULL); } errno = olderrno;
return; }
|
处理ctrl+c中断,发送终止进程给前台进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void sigint_handler(int sig) { int olderrno = errno; pid_t pid; sigset_t mask_all, prev_all; sigfillset(&mask_all); sigprocmask(SIG_BLOCK, &mask_all, &prev_all); if((pid = fgpid(jobs)) != 0){ sigprocmask(SIG_SETMASK, &prev_all, NULL); kill(-pid, SIGINT); }
errno = olderrno; return;
}
|
处理ctr+z中断,挂起前台进程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| void sigtstp_handler(int sig) { int olderrno = errno; pid_t pid; sigset_t mask_all, prev_all; sigfillset(&mask_all);
sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
if((pid = fgpid(jobs)) > 0){ sigprocmask(SIG_SETMASK, &prev_all, NULL); kill(-pid, SIGSTOP); }
errno = olderrno; return; }
|