diff --git a/shlab/tsh.c b/shlab/tsh.c index ee14e94..0a6bf8d 100644 --- a/shlab/tsh.c +++ b/shlab/tsh.c @@ -169,6 +169,8 @@ void eval(char *cmdline) char buf[MAXLINE]; // command will be parsed and modified? int bg; // whether it runs in background pid_t pid; + sigset_t mask; + sigemptyset(&mask); // preprocess cmd line strcpy(buf, cmdline); bg = parseline(buf, argv); // convert the command into argv @@ -179,26 +181,29 @@ void eval(char *cmdline) // run external command if (!builtin_cmd(argv)) // built-in command is done in `builtin_cmd` { - if ((pid = fork()) == 0) // this is child + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, NULL); // 5. block SIGCHLD + if ((pid = fork()) == 0) // this is child { + sigprocmask(SIG_UNBLOCK, &mask, NULL); // 5. unblock SIGCHLD + setpgid(0, 0); // put the child process (0=current) into a new process group (0=current) if (execve(argv[0], argv, environ) < 0) // execute command failed { printf("%s: Command not found\n", argv[0]); exit(0); // here only child exited } } - if (!bg) // run the process in foreground: + addjob(jobs, pid, bg ? BG : FG, cmdline); // add the job to job list. + // When bg=1, state=2; bg=0, state=1. this way it's just elegant + sigprocmask(SIG_UNBLOCK, &mask, NULL); // 5. unblock SIGCHLD + if (!bg) // run the process in foreground: // wait for foreground job to terminate { - int status; - if (waitpid(pid, &status, 0) < 0) // if return -1, then waiting failed - { - unix_error("waitfg: waitpid error"); - } + waitfg(pid); // the waiting stuff should be done in `waitfg` } else { - printf("%d %s", pid, cmdline); + printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline); // background job information } } return; @@ -271,6 +276,11 @@ int builtin_cmd(char **argv) { exit(0); } + if (strcmp(argv[0], "jobs") == 0) // t5: process jobs command + { + listjobs(jobs); + return 1; // this IS a builtin command, return 1 to notify + } return 0; /* not a builtin command */ } @@ -287,6 +297,10 @@ void do_bgfg(char **argv) */ void waitfg(pid_t pid) { + while (pid == fgpid(jobs)) + { + sleep(0); + } return; } @@ -303,6 +317,15 @@ void waitfg(pid_t pid) */ void sigchld_handler(int sig) { + pid_t pid; + int status; + while((pid=waitpid(-1,&status,WNOHANG|WUNTRACED))>0) // check if a child has become zombie, without wait + { + if(WIFEXITED(status)) + { + deletejob(jobs,pid); // remove pid from job list + } + } return; }