/* * 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. */ void sigchld_handler(int sig) { int pid = 1; int status ; while( pid >0 ){ pid=waitpid(-1,&status,WNOHANG|WUNTRACED); if( pid > 0){ if(WIFEXITED(status)){ // child exited normally //printf( "killed job [%d] , PID: %d with SIGINT \n", getjobpid(jobs, pid)->jid, getjobpid(jobs, pid)->pid ); deletejob(jobs,pid); } //child caught signal!! if(WIFSIGNALED(status)){ printf( "killed job [%d] , PID: %d with SIGINT \n", getjobpid(jobs, pid)->jid, getjobpid(jobs, pid)->pid ); deletejob(jobs,pid); // cntrl c so delete the job after kill is called } if(WIFSTOPPED(status)){ printf( "stopped job [%d] , PID: %d with SIGTSTP\n", getjobpid(jobs, pid)->jid, getjobpid(jobs, pid)->pid ); getjobpid(jobs, pid)->state=ST; // cntrl z so set the state to stop after kill is called } } } }
/* * 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. */ void sigchld_handler(int sig) { pid_t pid; int status; while((pid=waitpid(-1,&status,WNOHANG|WUNTRACED))>0) { if(WIFSIGNALED(status)) { struct job_t* tempjob; if((tempjob=getjobpid(jobs,pid))!=NULL) { printf("Job [%d] (%d) terminated by signal %d\n",tempjob->jid,tempjob->pid,WTERMSIG(status)); deletejob(jobs,pid); } continue; } if(WIFSTOPPED(status)) { struct job_t* tempjob; if((tempjob=getjobpid(jobs,pid))!=NULL) { if(tempjob->state!=ST) { printf("Job [%d] (%d) stopped by signal %d\n",tempjob->jid,tempjob->pid,SIGTSTP); tempjob->state=ST; } } continue; } deletejob(jobs,pid); } return; }
/* * 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. */ void sigchld_handler(int sig) { // Save current errno value int tempErrNo = errno; int status = 0; pid_t pid; if ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) { if (WIFEXITED(status)) { deletejob(jobs, pid); } else if (WIFSIGNALED(status)) { // Get the terminated job struct job_t* myJob = getjobpid(jobs, pid); // Print info on therminated job safe_printf("Job [%d] (%d) terminated by signal %d\n", myJob->jid, myJob->pid, WTERMSIG(status)); deletejob(jobs, pid); } else if (WIFSTOPPED(status)) { // Get the stopped job struct job_t* myJob = getjobpid(jobs, pid); // Change the state to stopped myJob->state = ST; // Print info on stopped job safe_printf("Job [%d] (%d) stopped by signal %d\n", myJob->jid, myJob->pid, WSTOPSIG(status)); } } else { if (errno != 0) { unix_error("Waitpid error"); } } // Restore errno value errno = tempErrNo; return; }
/* * 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. */ void sigchld_handler(int sig) { /* reaps all zombie and doesn't block */ pid_t reap_pid; int state = 0; /* used to determine what causes the SIGCHLD */ /* waitpid() return 0 immediately when no childs have terminated */ while (0 < (reap_pid = waitpid(-1, &state, WNOHANG))) { /* DBG(("reaped child %d", (int)reap_pid)); */ /*TODO Is it safe to call getjobpid(), deletejob(), clearjob() in the signal handler? */ if (WIFSIGNALED(state)) { struct job_t *termjob = getjobpid(jobs, reap_pid); fprintf(stdout, "hello Job [%d] (%d) terminated by signal %d\n", termjob->jid, termjob->pid, WTERMSIG(state)); } deletejob(jobs, reap_pid); clearjob(getjobpid(jobs, reap_pid)); } if (-1 == reap_pid && errno != ECHILD) unix_error("waitpid()"); /* if a job be suspended, we need to change its state here */ pid_t stp_pid; /* waitpid return 0 if there is no terminated process and stopped process */ while (0 < (stp_pid = waitpid(-1, &state, WNOHANG | WUNTRACED))) { struct job_t *stpjob = getjobpid(jobs, stp_pid); stpjob->state = ST; if (WIFSTOPPED(state)) { fprintf(stdout, "world Job [%d] (%d) stopped by signal %d\n", stpjob->jid, stpjob->pid, WSTOPSIG(state)); } } if (-1 == stp_pid && errno != ECHILD) unix_error("waitpid()"); }
/* * 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. */ void sigchld_handler(int sig) { pid_t pid; int status; while (( pid = waitpid(-1,&status, WNOHANG | WUNTRACED)) > 0) // reaping whatever is ready no hang { if(WIFSTOPPED(status) ) { if((getjobpid(jobs,pid)->state) != ST) { printf("Job [%d] (%d) Stopped by Signal %d\n",(getjobpid(jobs,pid))->jid, pid, SIGTSTP); } getjobpid(jobs, pid)->state = ST; return; } else if(WIFSIGNALED(status) && fgpid(jobs) ==pid ) { if(pid != 0){ printf("Job [%d] (%d) Terminated by Signal %d\n",(getjobpid(jobs,pid))->jid, pid, SIGINT); } kill(-pid,SIGINT); } deletejob(jobs, pid); } return; }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU signal. The * handler reaps all available zombie children, but doesn't wait * for any other currently running children to terminate. */ void sigchld_handler(int sig) { pid_t pid; int status; struct job_t *job; sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_BLOCK,&mask,NULL); while((pid=waitpid(-1,&status,WNOHANG|WUNTRACED))>0) { if(WIFSTOPPED(status)){ job = getjobpid(job_list,pid); job->state = ST; printf("Job [%d] (%d) stopped by signal %d\n",job->jid,job->pid,WSTOPSIG(status)); } else if(WIFSIGNALED(status)) { job=getjobpid(job_list,pid); printf("Job [%d] (%d) terminated by signal %d\n",job->jid,job->pid,WTERMSIG(status)); deletejob(job_list,pid); } else { deletejob(job_list,pid); } } sigprocmask(SIG_UNBLOCK,&mask,NULL); 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. */ void sigtstp_handler(int sig) { pid_t fpid = fgpid(jobs); // gets the fg process kill(-fpid, SIGTSTP); // sending to the fg process printf("Job [%d] (%d) Stopped by Signal %d\n",(getjobpid(jobs,fpid))->jid, fpid, SIGTSTP); getjobpid(jobs, fpid)->state = ST; return; }
/* * do_bgfg - Execute the builtin bg and fg commands */ void do_bgfg(char **argv) { struct job_t * selectedJob; if(argv[1] == NULL){ printf("Please include PID/JID in 2nd argument\n"); return; } if(argv[2] != NULL){ printf("Format should be: fg/bg PID/JID\n"); return; } if(argv[1][0] == '%' ){ // look for %n int jid = argv[1][1] - '0'; if( getjobjid(jobs, jid) == NULL){ //bad jid printf("Invalid JID\n"); return; } selectedJob = getjobjid(jobs, jid); } else if( atoi(argv[1] )){ // check if its a pid # int pid = atoi(argv[1]); if( getjobpid(jobs, pid) == NULL){ // bad pid printf("Invalid PID\n"); return; } selectedJob = getjobpid(jobs, pid); } else{ printf("Unkown job ID/pid entered! \n" ); return; } int pid = selectedJob->pid; if(strcmp(argv[0],"fg") == 0 ){ selectedJob->state = FG; kill(-pid, SIGCONT); waitfg(pid); } else if(strcmp(argv[0],"bg") == 0 ){ selectedJob->state = BG; kill(-pid, SIGCONT); } }
/* * do_bgfg - Execute the builtin bg and fg commands */ void do_bgfg(char **argv) { pid_t pid; if (argv[1][0] == '%') { pid_t jid = atoi(&argv[1][1]); struct job_t *job = getjobjid(jobs, jid); if (job == NULL){ printf("%s No such job\n", argv[1]); return; } pid = job->pid; } else pid = atoi(argv[1]); if(pid == 0) return; if (!strcmp(argv[0], "bg")) { if(kill(-pid, SIGCONT) != 0) printf("%s No such job\n", argv[1]); else { struct job_t *job = getjobpid(jobs, pid); job->state = BG; printf("[%d] (%d) %s\n", job->jid, job->pid, job->cmdline); } } else if(!strcmp(argv[0], "fg")) { if(kill(-pid, SIGCONT) != 0) printf("%s No such job\n", argv[1]); else { struct job_t *job = getjobpid(jobs, pid); job->state = FG; printf("[%d] (%d) %s\n", job->jid, job->pid, job->cmdline); int status; if(waitpid(pid, &status, WUNTRACED) > 0) { if(WIFEXITED(status) || WIFSIGNALED(status)) deletejob(jobs, job->pid); else if(WIFSTOPPED(status)) { job->state = ST; } } } } 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. */ void sigtstp_handler(int sig) { if (verbose) printf ("sigtstp_handler: entering\n"); /* send stop signal to foreground process and it's entire group */ pid_t pid = fgpid(jobs); if (getjobpid (jobs, pid) && verbose) printf ("sigtstp_handler: Job [%d] (%d) stopped\n", pid2jid (pid), pid); if (verbose) printf ("sigtstp_handler: exiting\n"); if (getjobpid (jobs, pid)) kill (-pid, sig); 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. */ void sigint_handler(int sig) { if (verbose) printf ("sigint_handler: entering\n"); /* send interrupt signal to foreground process and it's entire group */ pid_t pid = fgpid(jobs); if (getjobpid (jobs, pid) && verbose) printf ("sigint_handler: Job (%d) killed\n", pid); if (verbose) printf ("sigint_handler: exiting\n"); if (getjobpid (jobs, pid)) kill (-pid, sig); return; }
/* * 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. */ void sigchld_handler(int sig) { int status; // Status pid_t pid; // pid struct job_t *pjob; // Pointer to job do { // Following directions from the link in the README pid = waitpid(-1, &status, WNOHANG|WUNTRACED); // Using WNOHANG as spoken about in class if (pid > 0) { if (WIFSTOPPED(status)) { // If stopped if ((pjob = getjobpid(jobs, pid)) != NULL) { // get job and change state pjob->state = ST; // changing state printf("Job [%d] (%d) stopped by signal 20\n", pjob->jid, pjob->pid); } else { // Job was invalid printf("sigchld_handler: getjobpid error\n"); exit(1); } } else if (WIFSIGNALED(status)) { // TODO: Find the link for the second tutorial if ((pjob = getjobpid(jobs, pid)) != NULL) { printf("Job [%d] (%d) terminated by signal 2\n", pjob->jid, pjob->pid); if (!deletejob(jobs, pid)) { // Delete job printf("sigchld_handler: deletejob error\n"); exit(1); } } else { printf("sigchld_handler: getjobpid error\n"); exit(1); } } else if (WIFEXITED(status)) { if (!deletejob(jobs, pid)) { // DELETE JOB printf("sigchld_handler: deletejob error\n"); exit(1); } } else { printf("Unknown waitpid\n"); exit(1); } } else if (pid == -1 && errno == EINTR) { continue; } else { break; } } while (1); return; }
/* * do_bgfg - Execute the builtin bg and fg commands */ void do_bgfg(char **argv) { struct job_t *jd; int temp; if(!strcmp(argv[0], "bg")){ //bg command if(argv[1][0] == '%'){ temp=argv[1][1]; jd=getjobjid(jobs, temp-48); //get job id based on %input if(jd==NULL) printf("%s: No such job\n",argv[1]);} else{ temp=atoi(argv[1]); jd=getjobpid(jobs, temp); //get job id based on input if(jd==NULL) printf("(%d): No such process\n",temp);} printf("[%d] (%d) %s",jd->jid,jd->pid,jd->cmdline); kill(jd->pid,SIGCONT); //send SIGCONT signal to process jd->state=BG; } if(!strcmp(argv[0], "fg")){ //fg command if(argv[1][0] == '%'){ temp=argv[1][1]; jd=getjobjid(jobs, temp-48); //get job id based on %input if(jd==NULL) printf("%s: No such job\n",argv[1]);} else{ temp=atoi(argv[1]); jd=getjobpid(jobs, temp); //get job id based on input if(jd==NULL) printf("(%d): No such process\n",temp);} if(jd!=NULL){ waitfg(jd->pid); kill(jd->pid,SIGCONT); //send sigcont to process if(jd->state!=ST) deletejob(jobs,jd->pid); //delete the job after termination } } return; }
/* * 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. */ void sigchld_handler(int sig) { pid_t child_pid; //Stores the child pid int status; //Status variable while((child_pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0){ //Get the child pid in the loop struct job_t *jd = getjobpid(jobs, child_pid); //Get job detail of the child if(!jd){ //If no job printf("((%d): No such child", child_pid); //Throw error return; } if(WIFSTOPPED(status)){ //If stopped jd->state = ST; //Change state of job to stopped printf("Job [%d] (%d) stopped by signal 20\n",jd->jid, child_pid); //print the message } else if(WIFSIGNALED(status)){ //If signalled deletejob(jobs, child_pid); //Delete job from jobs list printf("Job [%d] (%d) terminated by signal 2\n", jd->jid, child_pid); } else if(WIFEXITED(status)){ //If exited deletejob(jobs, child_pid); //Delete from jobs list } else{ //If nothing unix_error("waitpid error"); //throw error } } return; }
void sigchld_handler(int sig) { pid_t pid = 0; struct job_t *nowjob = 0; int status; while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0)//handle all stopped or terminated children { if(WIFEXITED(status)) { // printf("pid [%d] terminated normally\n",pid); deletejob(jobs,pid); } else if(WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by signal %d\n",pid2jid(pid),pid,WTERMSIG(status)); deletejob(jobs,pid); } else if(WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status)); nowjob = getjobpid(jobs,pid); nowjob->state = ST; } } if((errno != ECHILD) && (errno != 0)) { unix_error("waitpid error"); } return; }
/* * do_bgfg - Execute the builtin bg and fg commands */ void do_bgfg(char **argv) { int jobid = -1; pid_t pid = -1; struct job_t *nowjob; //error messages if(argv[1] == NULL) { if(!strcmp(argv[0],"fg")) puts("fg command requires PID or %jobid argument"); else if(!strcmp(argv[0],"bg")) puts("bg command requires PID or %jobid argument"); return; } if((argv[1][0] != '%') && (!(('0'<=argv[1][0]) && (argv[1][0]<='9')))) { if(!strcmp(argv[0],"fg")) puts("fg: argument must be a PID or %jobid"); else if(!strcmp(argv[0],"bg")) puts("bg: argument must be a PID or %jobid"); return; } //decide whether jid or pid if(argv[1][0] == '%') { jobid = atoi(&argv[1][1]); nowjob = getjobjid(jobs,jobid); } else { pid = (pid_t)atoi(argv[1]); nowjob = getjobpid(jobs,pid); } if(nowjob == NULL) { if(argv[1][0] == '%') printf("%%%d: No such job\n",jobid); else printf("(%d): No such process\n",(int)pid); return; } ////////////// if(!strcmp(argv[0],"bg")) { nowjob->state = BG; printf("[%d] (%d) %s",nowjob->jid,nowjob->pid,nowjob->cmdline); if(kill(-(nowjob->pid), SIGCONT)<0) unix_error("kill error"); } else if(!strcmp(argv[0],"fg")) { nowjob->state = FG; // printf("[%d] (%d) %s\n",nowjob->jid,nowjob->pid,nowjob->cmdline); if(kill(-(nowjob->pid), SIGCONT)<0) unix_error("kill error"); waitfg(nowjob->pid); } return; }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU signal. The * handler reaps all available zombie children, but doesn't wait * for any other currently running children to terminate. */ void sigchld_handler(int sig) { pid_t pid; int status; struct job_t *job; int old_err = errno; while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0 ) { if(WIFSTOPPED(status)) { job = getjobpid(job_list, pid); //Assume that pointer job is not NULL safe_printf("Job [%d] (%d) stopped by signal %d\n", job->jid, job->pid, WSTOPSIG(status)); job->state = ST; } else if(WIFSIGNALED(status)) { safe_printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); deletejob(job_list,pid); } else if(WIFEXITED(status)) deletejob(job_list,pid); } if( pid < 0 && errno != ECHILD && errno != EINTR ) { safe_printf("waitpid error: %s\n", strerror(errno)); _exit(1); } errno = old_err; return; }
/* id2job - parse the id and get job */ struct job_t * id2job(struct cmdline_tokens *tok, int argc) { struct job_t *job_ins = NULL; int job_id; int p_id; if ((tok -> argv[argc - 1][0]) == '%') { /* Start with %, parse it as jid */ job_id = atoi(tok -> argv[argc - 1] + 1); /* Skip % */ if ((job_ins = getjobjid(job_list, job_id)) == NULL) { printf("%%%d: No such job\n", job_id); } } else if (isdigit(tok -> argv[argc - 1][0])) { /* Start with number, parse it as pid */ p_id = atoi(tok -> argv[argc - 1]); if ((job_ins = getjobpid(job_list, p_id)) == NULL) { printf("(%d): No such process\n", p_id); } } else { if (BUILTIN_BG == (tok -> builtins)) { printf("bg: argument must be a pid or %%jobid\n"); } else if (BUILTIN_FG == (tok -> builtins)) { printf("fg: argument must be a pid or %%jobid\n"); } } return job_ins; }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU signal. The * handler reaps all available zombie children, but doesn't wait * for any other currently running children to terminate. */ void sigchld_handler(int sig) { int status; pid_t pid; while((pid = waitpid(-1, &status, WUNTRACED | WNOHANG)) > 0) { // If child exited normally, delete job from list if(WIFEXITED(status)) deletejob(job_list, pid); // If child terminated because of uncaught signal, delete job from list else if(WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); deletejob(job_list, pid); } // If child was stopped change status to ST else if(WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status)); getjobpid(job_list, pid) -> state = ST; } } return; }
/* * 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. */ void sigchld_handler(int sig) { // Jung driving now int status; pid_t pid; struct job_t *job; const int STDOUT = 1; /* check either status of children or return if no child zombied */ while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) { job = getjobpid(jobs, pid); if (WIFSTOPPED(status)) { /* stopped or ctrl+z */ job->state = ST; char buffer[100]; sprintf(buffer, "Job [%d] (%d) stopped by signal %d\n", job->jid, job->pid, WSTOPSIG(status)); write(STDOUT, buffer, strlen(buffer)); } else { if (WIFSIGNALED(status)) { /* terminated or ctrl+c */ char buffer[100]; sprintf(buffer, "Job [%d] (%d) terminated by signal %d\n", job->jid, job->pid, WTERMSIG(status)); write(STDOUT, buffer, strlen(buffer)); } deletejob(jobs, pid); /* delete job in all other cases */ } } return; // end of Jung driving, Kyung driving now }
/* * 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. */ void eval(char *cmdline) { // Kyung and Jung drove here /* Outline taken from Bryant & O'Hall page 735 */ /* variables*/ char *argv[MAXARGS]; char buf[MAXLINE]; int bg; pid_t pid; struct job_t *addedjob; sigset_t mask; /* for signals */ sigemptyset(&mask); sigaddset(&mask, SIGCHLD); strcpy(buf,cmdline); /* parse command line */ bg = parseline(buf,argv); /************************** * evaluates command line **************************/ if(argv[0] == NULL) return; if(!builtin_cmd(argv)) { /* built-in command */ sigprocmask(SIG_BLOCK, &mask, NULL); pid = fork(); if(pid < 0) { /* fork error handling */ unix_error("Fork error"); } else if(pid==0) { /* child */ setpgid(0, 0); sigprocmask(SIG_UNBLOCK, &mask, NULL); if(execve(argv[0], argv,environ) < 0) { printf("%s: Command not found\n", argv[0]); exit(1); } } else { /* parent - not a build-in command */ if(bg) { /* run in background */ sigprocmask(SIG_UNBLOCK, &mask, NULL); addjob(jobs, pid, BG, cmdline); addedjob = getjobpid(jobs,pid); printf("[%d] (%d) %s", addedjob->jid, addedjob->pid, addedjob->cmdline); } else { /* run in foreground */ sigprocmask(SIG_UNBLOCK, &mask, NULL); addjob(jobs, pid, FG, cmdline); waitfg(pid); } } } return; /* done with code excerpt/outline */ // end of Kyung and Jung driving }
/* * 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. */ void sigtstp_handler(int sig) { pid_t fg_pid = fgpid(jobs); if(fg_pid == 0) return ; #ifdef DEBUG_SIGTSTP printf("--------------SIGTSTP-----------------\n"); printf("fg_pid = %d\n",fg_pid); listjobs(jobs); #endif struct job_t* fg_job = getjobpid(jobs, fg_pid); printf("Job [%d] (%d) stopped by signal %d\n", fg_job->jid, fg_job->pid, sig); fg_job->state = ST; kill(-fg_pid, SIGTSTP); #ifdef DEBUG_SIGTSTP printf("after kill"); listjobs(jobs); printf("--------------------------------------\n"); #endif return; }
/* * 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. */ void sigchld_handler(int sig) { #ifdef DEBUG_SIGTSTP printf("--------------SIGCHLD-----------------\n"); listjobs(jobs); fflush(stdout); #endif pid_t pid; int status; while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0){ #ifdef DEBUG_SIGTSTP printf("pid = %d\n", pid); printf("WIFEXITED(status) = %d\n",WIFEXITED(status)); #endif if(WIFSTOPPED(status)){ getjobpid(jobs, pid)->state = ST; continue; } deletejob(jobs, pid); } #ifdef DEBUG_SIGTSTP printf("pid=%d\n",pid); listjobs(jobs); printf("---------------------------------------\n"); fflush(stdout); #endif return; }
void sigchld_handler(int sig) { int status; pid_t pid=0; struct job_t* job; while((pid=waitpid(-1,&status,WNOHANG|WUNTRACED))>0){ job=getjobpid(jobs,pid); if(WIFEXITED(status)) deletejob(jobs,pid); else { if(WIFSIGNALED(status)) { if(WTERMSIG(status)==2) { printf("Job [%d] (%d) terminated by signal 2\n",job->jid,pid); deletejob(jobs,pid); } } if(WIFSTOPPED(status)){ job->state=ST; printf("Job [%d] (%d) stopped by signal 20\n",job->jid,pid); } } } return; }
/* * do_bgfg - Execute the builtin bg and fg commands */ void do_bgfg(char **argv) { struct job_t * job; job = NULL; if (argv[1] == NULL) { // Missing arguments printf("%s command requires PID or %%jobid argument\n", argv[0]); fflush(stdout); return; } if (isdigit(*argv[1])) { // Check if the second argument is a digit job = getjobpid(jobs, atoi(argv[1])); if (!job) { printf("(%s): No such process\n", argv[1]); fflush(stdout); return; } } else if (strlen(argv[1]) > 1 && argv[1][0] == '%') { // Check if the second argument is %number (e.g. %5) if (isdigit(argv[1][1])) { // Make sure that the second character is a digit job = getjobjid(jobs, atoi(argv[1]+1)); if (!job) { printf("%s: No such job\n", argv[1]); fflush(stdout); return; } } } if (job == NULL) { // If the job is null, report invalid argument and stop printf("%s: argument must be a PID or %%jobid\n", argv[0]); fflush(stdout); return; } if (!strcmp(argv[0], "fg")) { if (Kill(-job->pid, SIGCONT) == 0) { job->state = FG; // since sigcont will just run the program in the background, // we need to explicitly tell the shell // to wait for it to complete waitfg(job->pid); } } else if (!strcmp(argv[0], "bg")) { // Restart job but do not wait for the job (job is in background) printf("[%i] (%i) %s", job->jid, job->pid, job->cmdline); fflush(stdout); if (Kill(-job->pid, SIGCONT) == 0) { job->state = BG; } } fflush(stdout); return; }
/* *fg_job - restart a stopped job and put it to foreground */ void fg_job(struct cmdline_tokens* tok) { pid_t pid; struct job_t* job; int jid; sigset_t mask; sigemptyset(&mask); int argc=tok->argc; if(tok->argv[argc-1][0]=='%') //recognizing the process by job ID { jid=atoi(tok->argv[argc-1]+1); job=getjobjid(job_list,jid); pid=job->pid; }else{ //recognizing the process by process ID pid=atoi(tok->argv[argc-1]); job=getjobpid(job_list,pid); } job->state=FG; kill(pid,SIGCONT); /* since the job state is changed to foreground, the parent process shall wait*/ while(fgpid(job_list)) { sigsuspend(&mask); } }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU signal. The * handler reaps all available zombie children, but doesn't wait * for any other currently running children to terminate. */ void sigchld_handler(int sig) { pid_t cpid; int status; struct job_t* job; sigset_t mask,prev; //the reason why i dn not use the wrapped function //is that i need the return value while ((cpid = waitpid(-1, &status,WNOHANG|WUNTRACED))>0) { //prepare the mask Sigfillset(&mask); //block the signal because i want to change something Sigprocmask(SIG_BLOCK, &mask, &prev); //get the job by the pid job = getjobpid(job_list, cpid); //STP by any signal //change thet status and print msg if (WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n",job->jid, cpid, WSTOPSIG(status)); job->state = ST; } //terminate by signal //delete the job and print msg else if (WIFSIGNALED(status)){ printf("Job [%d] (%d) terminated by signal %d\n",job->jid, cpid, WTERMSIG(status)); deletejob(job_list, cpid); } //terminate normally //just delete the job from the job list else deletejob(job_list, cpid); } return; }
/* Execute the built-in background command */ void bgjob(struct cmdline_tokens *tokens_ptr){ struct job_t *job_ptr = NULL; int argc = tokens_ptr->argc; char **argv = tokens_ptr->argv; int jid, pid; if(argv[argc - 1][0] == '%') { /* if job id is given */ jid = atoi(argv[argc - 1] + 1); job_ptr = getjobjid(job_list, jid); if(job_ptr == NULL){ fprintf(stderr, "Error: job with jid %d does not exist\n", jid); return ; } } else{ /* if process id is given */ pid = atoi(argv[argc - 1]); job_ptr = getjobpid(job_list, pid); if(job_ptr == NULL){ fprintf(stderr, "Error: job with pid %d does not exist\n", pid); return ; } } if(job_ptr->state == ST){ /* update the status, send SIGCONT signal and print information of the job*/ job_ptr->state = BG; kill(job_ptr->pid, SIGCONT); printf("[%d] (%d) %s\n", job_ptr->jid, job_ptr->pid, job_ptr->cmdline); } }
/* * 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. */ void sigtstp_handler(int sig) { struct job_t *job=getjobpid(jobs,fgpid(jobs)); if(job!=NULL) kill(-fgpid(jobs),SIGTSTP); return; }
/* * 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, SIGTSTP, SIGTTIN or SIGTTOU signal. The * handler reaps all available zombie children, but doesn't wait * for any other currently running children to terminate. */ void sigchld_handler(int sig) { int status; pid_t pid; while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { if(WIFEXITED(status)) { /* if a child job terminated normally */ deletejob(job_list, pid); } else if(WIFSIGNALED(status)) { /* if a child job terminated by signal */ printf("Job [%d] (%d) terminated by signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); deletejob(job_list, pid); } else if(WIFSTOPPED(status)) { /* if a child job is stopped, we should also update its status */ printf("Job [%d] (%d) stopped by signal %d\n", pid2jid(pid), pid, WSTOPSIG(status)); getjobpid(job_list, pid) -> state = ST; } } return; }