/* * eval - Evaluate the command line that the user has just typed in * * If the user has requested a built-in command (quit, jobs, bg or fg) * then execute it immediately. Otherwise, fork a child process and * run the job in the context of the child. If the job is running in * the foreground, wait for it to terminate and then return. Note: * each child process must have a unique process group ID so that our * background children don't receive SIGINT (SIGTSTP) from the kernel * when we type ctrl-c (ctrl-z) at the keyboard. */ voideval(char *cmdline) { char *argv[MAXARGS]; // Argument list char buf[MAXLINE]; // Holds modified command line int bg; // Should the job run in background or foreground pid_t pid; // Process id sigset_t mask; strcpy(buf,cmdline); bg = parseline(buf,argv); if(argv[0] == NULL){ return; // Ignore empty line }
/* * waitfg - Block until process pid is no longer the foreground process */ voidwaitfg(pid_t pid) { structjob_t* job; job = getjobpid(jobs,pid); while(job->state == FG){ sleep(1); } return; }
/***************** * Signal handlers *****************/
/* * sigchld_handler - The kernel sends a SIGCHLD to the shell whenever * a child job terminates (becomes a zombie), or stops because it * received a SIGSTOP or SIGTSTP signal. The handler reaps all * available zombie children, but doesn't wait for any other * currently running children to terminate. */ voidsigchld_handler(int sig) { int status; pid_t pid;
while ((pid = waitpid(fgpid(jobs), &status, WNOHANG | WUNTRACED)) > 0) { if (WIFSTOPPED(status)){ //change state if stopped getjobpid(jobs, pid)->state = ST; int jid = pid2jid(pid); printf("Job [%d] (%d) Stopped by signal %d\n", jid, pid, WSTOPSIG(status)); } elseif (WIFSIGNALED(status)){ //delete is signaled int jid = pid2jid(pid); printf("Job [%d] (%d) terminated by signal %d\n", jid, pid, WTERMSIG(status)); deletejob(jobs, pid); } elseif (WIFEXITED(status)){ //exited deletejob(jobs, pid); } } return; }
/* * sigint_handler - The kernel sends a SIGINT to the shell whenver the * user types ctrl-c at the keyboard. Catch it and send it along * to the foreground job. */ voidsigint_handler(int sig) { int pid = fgpid(jobs); if(pid == 0){ return; } kill(-pid,sig); return; }
/* * sigtstp_handler - The kernel sends a SIGTSTP to the shell whenever * the user types ctrl-z at the keyboard. Catch it and suspend the * foreground job by sending it a SIGTSTP. */ voidsigtstp_handler(int sig) { int pid = fgpid(jobs); if(pid == 0){ return; } kill(-pid,sig); return; }