深入理解计算机系统(CSAPP) 实验详解:ShellLab
生活随笔
收集整理的這篇文章主要介紹了
深入理解计算机系统(CSAPP) 实验详解:ShellLab
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
提示
- 利用測試文件逐步構建tsh,例如先從trace01.txt開始。
- 當在進程在前臺運行時(例如我們的tsh),你鍵入Ctrl+C,那么內核就會發送一個SIGINT信號(信號代碼2)給這個前臺進程組中的每個進程。也就是說假如你開始創建子進程的時候,沒有將子進程的進程組給設置到另外一個進程組(因為創建子進程的進程組ID默認是父進程的進程組ID),那么這個終止信號將會發送到你每一個創建的子進程中,包括前臺和后臺。然后會就導致你的程序出現bug,sigchld_handler可能會比sigint_handler運行的還快,因為你自己直接把子進程都給殺死了。
解決方法就是將我們創建的子進程分到外面去就行了,就如同上圖的pid=32,和pid=40一樣。創建子進程的時候調用函數setgpid(0,0)即可。 - 當子進程從停止狀態恢復時,父進程的sigchld_handler也會接受到信號,此時可能會導致一個bug產生,就是父進程會一直掛起等待恢復的子進程結束。
貼上代碼
void eval(char *cmdline) {char *argv[MAXLINE];/* param array */int bg = parseline(cmdline,argv);pid_t pid = 0;sigset_t mask,prev;sigemptyset(&mask);sigaddset(&mask,SIGCHLD);if(argv[0] == NULL)return;if(!builtin_cmd(argv)){if(access(argv[0],F_OK)){printf("文件不存在!\n");return;}sigprocmask(SIG_BLOCK,&mask,&prev);if((pid = fork())==0) // 子進程{sigprocmask(SIG_SETMASK,&prev,NULL);setpgid(0,0); // 將該子進程獨立變成一個獨立的進程if(!execv(argv[0],argv)){printf("輸入的參數有誤!!\n");_exit(0);}}else // 父進程{if(!bg){addjob(jobs,pid,FG,cmdline);sigprocmask(SIG_SETMASK,&prev,NULL);fg_flag = 1;waitfg(pid);}else{addjob(jobs,pid,BG,cmdline);struct job_t *job = getjobpid(jobs,pid);printf("[%d] (%d) %s\n",job->jid,pid,cmdline);sigprocmask(SIG_SETMASK,&prev,NULL);}}}return; }int builtin_cmd(char **argv) {if(!strcmp(argv[0],"quit"))exit(0);if(!strcmp(argv[0],"&"))return 1;if(!strcmp(argv[0],"jobs")){listjobs(jobs);return 1;}if(!strcmp(argv[0],"fg") || !strcmp(argv[0],"bg")){do_bgfg(argv);return 1;}return 0; /* not a builtin command */ }void do_bgfg(char **argv) {struct job_t* job = NULL;if(!strcmp(argv[0],"bg")){if(argv[1] == NULL){printf("bg command requires PID or %%jobid argument\n");return ;}if(argv[1][0]=='%'){job = getjobjid(jobs,atoi(argv[1]+1));if(!job){printf("%s: No such job\n",argv[1]);return ;}}else{if(atoi(argv[1]) == 0){printf("bg: argument must be a PID or %%jobid\n");return;}job = getjobpid(jobs,atoi(argv[1]));if(!job){printf("(%s): No such process\n",argv[1]);return ;}}job->state = BG;printf("[%d] (%d) %s\n",job->jid,job->pid,job->cmdline);stopped_resume_child = job->pid;killpg(job->pid,SIGCONT);return;}if(!strcmp(argv[0],"fg")){if(argv[1] == NULL){printf("fg command requires PID or %%jobid argument\n");return;}if(argv[1][0]=='%'){job = getjobjid(jobs,atoi(argv[1]+1));if(!job){printf("%s: No such job\n",argv[1]);return ;}}else{if(atoi(argv[1]) == 0){printf("fg: argument must be a PID or %%jobid");return;}job = getjobpid(jobs,atoi(argv[1]));if(!job){printf("(%s): No such process\n",argv[1]);return ;}}if(job->state != ST){job->state = FG;fg_flag = 1;waitfg(job->pid);return;}if(job->state == ST){job->state = FG;fg_flag = 1;stopped_resume_child = job->pid;killpg(job->pid,SIGCONT);fg_flag = 1;waitfg(job->pid);return;}}return; }void waitfg(pid_t pid) {while (fg_flag){sleep(0);}return; }void sigchld_handler(int sig) {if(stopped_resume_child>0){stopped_resume_child = 0;return;}pid_t pid = 0;int status;struct job_t *job = NULL;if((pid = waitpid(-1,&status,WUNTRACED))>0){fg_flag = 0;/* 解開前臺鎖 */ if(WIFEXITED(status)) /* 正常退出時才可刪除任務 */{deletejob(jobs,pid);}else if(WIFSIGNALED(status)){job = getjobpid(jobs,pid);printf("job [%d] (%d) terminated by signal 2\n",job->jid,pid);deletejob(jobs,pid);}else{job = getjobpid(jobs,pid);printf("job [%d] (%d) stopped by signal 20\n",job->jid,pid);}}return; }void sigint_handler(int sig) {pid_t pid = 0;if((pid = fgpid(jobs))==0){printf("找不到任何的前臺任務!\n");return;}killpg(pid,SIGINT);return; }void sigtstp_handler(int sig) {pid_t pid = 0;struct job_t* job = NULL;if((pid = fgpid(jobs))==0){printf("找不到任何的前臺任務!\n");return;}fg_flag = 1;job = getjobpid(jobs,pid);job->state = ST;killpg(pid,SIGTSTP);return; }參考博客
李秋豪
總結
以上是生活随笔為你收集整理的深入理解计算机系统(CSAPP) 实验详解:ShellLab的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【翻译】Designing Websit
- 下一篇: java信息管理系统总结_java实现科