/* * 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; while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { struct job_t *job = getjobpid(job_list, pid); if (WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by signal %d\n", job->jid, pid, WTERMSIG(status)); deletejob(job_list, pid); } else if (WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n", job->jid, pid, WSTOPSIG(status)); job->state = ST; } else { deletejob(job_list, 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) { int olderrno = errno; sigset_t mask_all, prev_all; pid_t pid; int status; Sigfillset(&mask_all); while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) { Sigprocmask(SIG_BLOCK, &mask_all, &prev_all); /* Block Signals*/ if (WIFEXITED(status)) { /* Exit normally */ deletejob(jobs, pid); } if (WIFSIGNALED(status)) { /* C-c SIGINT */ printf("Job [%d] (%d) terminated by signal 2\n", pid2jid(pid), pid); deletejob(jobs, pid); /* Note: printf first, then deletejob */ } if (WIFSTOPPED(status)) { /* C-z SIGTSTP */ printf("Job [%d] (%d) stopped by signal 20\n", pid2jid(pid), pid); getjobpid(jobs, pid)->state = ST; } Sigprocmask(SIG_SETMASK, &prev_all, NULL); /* Unblock Signals*/ } errno = olderrno; return; }
/* * waitfg - Block until process pid is no longer the foreground process */ void waitfg(pid_t pid) { int status; if ((pid = waitpid(pid, &status, WUNTRACED)) < 0) { perror("waitfg error:"); exit(0); } else { if (WIFSTOPPED(status)) { int jid = pid2jid(pid); printf("Job [%d] %d stopped by signal: Stopped\n",jid,(int)pid); } else if (WIFEXITED(status)) { deletejob(jobs,pid); } else if (WIFSIGNALED(status)) { printf("Job %d terminated by signal: Interrupt\n",(int)pid); 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) { struct job_t *job; int status; pid_t pid; while((pid=waitpid(-1,&status,WNOHANG|WUNTRACED))>0) //returns pid of child if OK,0 or -1 on error { job = getjobpid(jobs,pid); if(WIFEXITED(status)) { deletejob(jobs,pid);//deleting jobs if exited normally } if(WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by signal %d\n",job->jid,pid,WTERMSIG(status)); deletejob(jobs,pid); //deleting jobs terminated with signals } if(WIFSTOPPED(status)) { printf("Job [%d] (%d) stopped by signal %d\n",job->jid,pid,WSTOPSIG(status)); job->state = ST; //changing the state of stopped jobs to ST } } return; }
void fg_waitpid(pid_t pid) { int status; pid_t r_pid; struct job *p; if ((r_pid = waitpid(pid, &status, 0)) > 0) { printf("fg_waitpid in, forepid=%d, r_pid=%d\n", forepid, r_pid); forepid = 0; if (WIFEXITED(status)) { deletejob(r_pid); fprintf(stderr, "job %d terminated normally with exit status=%d\n", r_pid, WEXITSTATUS(status)); } else if (WIFSTOPPED(status)) { p = selectjob(r_pid); p->state = 0; fprintf(stderr, "job [%d] %d stopped by signal: Stopped\n", p->jid, r_pid); } else if (WIFSIGNALED(status)) { deletejob(r_pid); fprintf(stderr, "job %d terminated by ", r_pid); psignal(WTERMSIG(status), "signal"); } } else if (errno != ECHILD) fprintf(stderr, "waitpid error: %s\n", strerror(errno)); printf("foreground reaped pid=%d, ready to return\n", r_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) { 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) { // 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) { 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) { struct job_t *jd; pid_t pid; int status = -1; //returns 0 if working correctly, and will return -1 if it errors out while((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0){ jd = getjobpid(jobs, pid); if(WIFEXITED(status)){ deletejob(jobs, pid); } if(WIFSIGNALED(status)){ printf("[%d] (%d) terminated by signal 2\n",jd->jid, pid); deletejob(jobs, pid); } if(WIFSTOPPED(status)){ printf("[%d] (%d) terminated by signal 20\n",jd->jid, pid); jd->state = ST; } } return; }
void sigchld_handler(int sig) { pid_t pid; int status; struct job *p; if ((pid = waitpid(-1, &status, WUNTRACED)) > 0) { if (pid == forepid) forepid = 0; if (WIFEXITED(status)) deletejob(pid); else if (WIFSTOPPED(status)) { p = selectjob(pid); p->state = 0; fprintf(stderr, "job [%d] %d stopped by signal: Stopped\n", p->jid, pid); } else if (WIFSIGNALED(status)) { deletejob(pid); fprintf(stderr, "job %d terminated by ", pid); psignal(WTERMSIG(status), "signal"); } } else if (errno != ECHILD) fprintf(stderr, "\nwaitpid error: %s\n", strerror(errno)); return; }
void fg_waitpid(pid_t pid) { int status; pid_t r_pid = 0; struct job *p = NULL; if ((r_pid = waitpid(pid, &status, 0)) > 0) { forepid = 0; if (WIFEXITED(status)) deletejob(r_pid); else if (WIFSTOPPED(status)) { p = selectjob(r_pid); p->state = 0; fprintf(stderr, "job [%d] %d stopped by signal: Stopped\n", p->jid, r_pid); } else if (WIFSIGNALED(status)) { deletejob(r_pid); fprintf(stderr, "job %d terminated by ", r_pid); psignal(WTERMSIG(status), "signal"); } } else if (errno != ECHILD) fprintf(stderr, "waitpid error: %s\n", strerror(errno)); 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 pid; int status; // Reap all the child process. while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { //Handle with the 3 situation in this handler together. if (WIFSIGNALED(status)) { printf("Job [%d] (%d) terminated by Signal %d\n", pid2jid(pid), pid, WTERMSIG(status)); deletejob(jobs, pid); } else if ( WIFSTOPPED(status)) { struct job_t *job = getjobpid(jobs, pid); if (job == NULL) { printf("sigchld: Get job error.\n"); return; } job->state = ST; printf("Job [%d] (%d) stopped by Signal %d\n", pid2jid(pid), pid, WEXITSTATUS(status)); } else if ( WIFEXITED(status)) { deletejob(jobs, pid); } //printf("Handler reaped child %d\n", (int)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) { int status; if (verbose) printf ("sigchld_handler: entering\n"); /* wait until some child is terminated */ pid_t pid_ch, jid_ch ; while ((pid_ch = waitpid (-1, &status, WUNTRACED | WNOHANG)) > 0) { // wait any terminated child jid_ch = pid2jid (pid_ch); if (verbose) printf ("sigchld_handler: Job [%d] (%d) deleted\n", jid_ch, pid_ch); if (WIFEXITED (status)) { // case 1: child process terminated normally if (verbose) printf ("sigchld_handler: Job [%d] (%d) terminates OK (status 0)\n", jid_ch, pid_ch); deletejob (jobs, pid_ch); } else if (WIFSIGNALED (status)) { // case 2: child process terminated via a signal that was not caught deletejob (jobs, pid_ch); printf ("Job [%d] (%d) terminated by signal %d\n", jid_ch, pid_ch, WTERMSIG (status)); } else if (WIFSTOPPED (status)) { // case 3: child process stopped struct job_t *stopped = getjobpid (jobs, pid_ch); stopped->state = ST; printf ("Job [%d] (%d) stopped by signal %d\n", jid_ch, pid_ch, WSTOPSIG (status)); } } if (verbose) printf ("sigchld_handler: exiting\n"); 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; 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)); } else if (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); } else if (WIFEXITED(status)){ //exited 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) { //Throw out finished processes //Change status to ST for stopped processes int child_status; pid_t culprit_pid; //pid of terminated or stopped child, 0 if no child terminated/stopped, -1 err pid_t culprit_jid; while((culprit_pid = waitpid(-1, &child_status, WNOHANG | WUNTRACED)) > 0) { culprit_jid = pid2jid(culprit_pid); if (WIFEXITED(child_status)) { //Child terminated normally, via a call to exit or a return if (verbose) printf("child %d exited normally\n", culprit_pid); deletejob(jobs, culprit_pid); } else if (WIFSIGNALED(child_status)) { //Child terminated because of a signal that was not caught if (verbose) printf("child %d exited because of a signal\n", culprit_pid); deletejob(jobs, culprit_pid); printf("Job [%d] (%d) terminated by signal %d", culprit_jid, culprit_pid, WTERMSIG(child_status)); printf("\n"); } else if (WIFSTOPPED(child_status)) { //Child that caused the return is stopped if (verbose) printf("child %d stopped\n", culprit_pid); //Change job list state to stopped struct job_t *myJob = getjobpid(jobs, culprit_pid); myJob->state = ST; printf("Job [%d] (%d) stopped by signal %d", culprit_jid, culprit_pid, WSTOPSIG(child_status)); printf("\n"); } } }
/* * 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; int olderrno = errno; // store errno in handler /* * Reap child with the pid if the child is stopped or terminated * If a child is terminated normally, delete the child from the job list * If a child is stopped by a signal, set the job status as stopped * If a child is terminated by a signal that was not caught, delete the child from the job list */ while ((pid = waitpid(-1, &status, WNOHANG|WUNTRACED)) > 0) { if (WIFEXITED(status)) { deletejob(job_list, pid); // the child ternimated normally } else if (WIFSTOPPED(status)) { /* * Avoid printf() in handler, use helper function to write the output to stdout */ sio_puts("Job ["); sio_putl(pid2jid(pid)); sio_puts("] ("); sio_putl(pid); sio_puts(") stopped by signal "); sio_putl(WSTOPSIG(status)); sio_puts("\n"); getjobpid(job_list, pid) -> state = ST; // the child was stopped by a signal } else if (WIFSIGNALED(status)) { // the child was terminated by a signal that was not caught /* * Avoid printf() in handler, use helper function to write the output to stdout */ sio_puts("Job ["); sio_putl(pid2jid(pid)); sio_puts("] ("); sio_putl(pid); sio_puts(") terminated by signal "); sio_putl(WTERMSIG(status)); sio_puts("\n"); deletejob(job_list, pid); } } errno = olderrno; 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 child_status; // child process status for waitpid pid_t wpid; struct job_t *job; // wait for child process while there is any child left while(maxjid(jobs)) { // -1 : wait for any child // WNOHANG : don't block procedure // WUNTRACED : trace stopped child wpid = waitpid(-1, &child_status, WNOHANG | WUNTRACED); if(wpid == -1) { // handle waitpid error perror("waitpid"); return; } else if(wpid == 0) { // no child was terminated or stopped break; } // find job object with pid // getjobpid never fails job = getjobpid(jobs, wpid); // check child status if(WIFSIGNALED(child_status)) { // child terminated by a signal printf("Job [%d] (%d) terminated by signal %d\n", job->jid, job->pid, WTERMSIG(child_status)); // delete job from job list deletejob(jobs, wpid); } else if(WIFSTOPPED(child_status)) { // child stopped printf("Job [%d] (%d) stopped by signal %d\n", job->jid, job->pid, WSTOPSIG(child_status)); // set state job->state = ST; } else if(WIFEXITED(child_status)) { // child exited properly // delete job from job list deletejob(jobs, wpid); } } }
void sigchld_handler(int sig) { pid_t pid; int status; struct job *p; if ((pid = waitpid(-1, &status, WUNTRACED)) > 0) { if (WIFEXITED(status)) { deletejob(pid); if (pid == forepid) { forepid = 0; setpgid(pid, pid); fprintf(stderr, "foreground job %d terminated normally with exit status=%d\n", pid, WEXITSTATUS(status)); siglongjmp(env, 1); } else fprintf(stderr, "job %d terminated normally with exit status=%d\n", pid, WEXITSTATUS(status)); } else if (WIFSTOPPED(status)) { p = selectjob(pid); p->state = 0; if (pid == forepid) { forepid = 0; setpgid(pid, pid); fprintf(stderr, "foreground job [%d] %d stopped by signal: Stopped\n", p->jid, pid); siglongjmp(env, 1); } else fprintf(stderr, "job [%d] %d stopped by signal: Stopped\n", p->jid, pid); } else if (WIFSIGNALED(status)) { deletejob(pid); if (pid == forepid) { forepid = 0; setpgid(pid, pid); fprintf(stderr, "foreground job %d terminated by ", pid); psignal(WTERMSIG(status), "signal"); siglongjmp(env, 1); } else fprintf(stderr, "job %d terminated by ", pid); psignal(WTERMSIG(status), "signal"); } } else if (errno != ECHILD) fprintf(stderr, "waitpid error: %s\n", strerror(errno)); printf("handler reaped pid=%d, ready to return right now.\n", 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) { 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; }
/* * builtin_cmd - If the user has typed a built-in command then execute * it immediately. */ int builtin_cmd(char **argv) { int r=0; char* p; int jobid; if(strcmp(argv[0],"quit")==0) { r++; exit(0); } else if(strcmp(argv[0],"jobs")==0) { r++; listjobs(jobs); } else if((strcmp(argv[0],"bg")==0)||(strcmp(argv[0],"fg")==0)) { r++; do_bgfg(argv); } else if(strcmp(argv[0],"kill")==0) { r++; p = strstr(argv[1],"%"); p++; jobid=atoi(p); //Since jobid is specified as %5 for job 5 we get 5 from argv[1]. jobid=getjobjid(jobs,jobid)->pid; kill(jobid,SIGKILL); deletejob(jobs,jobid); } return r; /* not a builtin command */ }
// delete delayed jobs void datacloud::deletedelayedjobs() { jobqueueelem *job,*prev; BOOLINT flag; job=JOBQUEUETAIL; while (job!=NULL) { flag=FALSE; if (job->hfield!=NULL) if (job->hfield->isdelayed) flag=TRUE; if (job->texture!=NULL) if (job->texture->isdelayed) flag=TRUE; if (job->fogmap!=NULL) if (job->fogmap->isdelayed) flag=TRUE; prev=job->prev; if (flag) deletejob(job); job=prev; } }
/* * 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 }
/* * 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; }
/* * waitfg - block until FG job pid terminates or stops. */ void waitfg(pid_t pid) { int status; /* wait for FG job to stop (WUNTRACED) or terminate */ if (waitpid(pid, &status, WUNTRACED) < 0) unix_error("waitfg: waitpid error"); /* FG job has stopped. Change its state in jobs list */ if (WIFSTOPPED(status)) { sprintf(sbuf, "Job %d stopped by signal", pid); psignal(WSTOPSIG(status), sbuf); updatejob(jobs, pid, ST); } /* FG job has terminated. Remove it from job list */ else { /* check if job was terminated by an uncaught signal */ if (WIFSIGNALED(status)) { sprintf(sbuf, "Job %d terminated by signal", pid); psignal(WTERMSIG(status), sbuf); } deletejob(jobs, pid); if (verbose) printf("waitfg: job %d deleted\n", pid); } }
/* * 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 info; pid_t pid; while ((pid = waitpid(fgpid(jobs), &info, WNOHANG|WUNTRACED)) > 0) { if (WIFSTOPPED(info)) // Job exited by external process { sigtstp_handler(20); } else if (WIFSIGNALED(info)) // job terminated due to faulty signal { sigint_handler(-2); } else if (WIFEXITED(info)) // Job exits normalls { deletejob(jobs, pid); } } if ((errno != ECHILD && pid == -1) || pid > 0) // After the loop pid is -1, or pid is 0 { unix_error("WAITPID ERROR 404"); } return; }
/* * builtin_cmd - If the user has typed a built-in command then execute * it immediately. */ int builtin_cmd(char **argv) { if (!strcmp(argv[0], "quit")) { exit(0); } if (!strcmp(argv[0], "jobs")) { listjobs(jobs); return 1; } if ((!strcmp(argv[0], "bg") || !strcmp(argv[0], "fg")) && (argv[1] != NULL)) { do_bgfg(argv); return 1; } if (!strcmp(argv[0], "kill")) { pid_t pid = atoi(argv[1]); kill(-pid, SIGKILL); if (getjobpid(jobs, pid) != NULL) { if (waitpid(pid, NULL, 0) < 0) unix_error("kill child process error"); deletejob(jobs, pid); } return 1; } return 0; /* not a builtin command */ }
/* * 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 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()"); }
/* $begin procmask */ void handler(int sig) { pid_t pid; while ((pid = waitpid(-1, NULL, 0)) > 0) /* Reap a zombie child */ deletejob(pid); /* Delete the child from the job list */ if (errno != ECHILD) unix_error("waitpid error"); }
/* * 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) { if(verbose) printf("sigchld_handler: entering\n"); int status; pid_t pid; pid = waitpid(-1,&status,WNOHANG | WUNTRACED); if(!pid) return; struct job_t *job = getjobpid(jobs,pid); //if child was killed by signal if(WIFSIGNALED(status)) { kill(-pid, SIGKILL); if(verbose) { printf("sigchld_handler: Job [%d] (%d) deleted\n", job->jid, pid); } printf("Job [%d] (%d) terminated by signal %d\n", job->jid, pid, WTERMSIG(status)); deletejob(jobs,pid); } //if child is stopped else if(WIFSTOPPED(status)) { job->state = ST; printf("Job [%d] (%d) stopped by signal %d\n", job->jid,pid,WSTOPSIG(status)); } //if child was killed normaly else if(WIFEXITED(status)) { kill(-pid, SIGKILL); if(verbose){ printf("sigchld_handler: Job [%d] (%d) deleted\n", job->jid, pid); printf("sigchld_handler: Job [%d] (%d) terminates OK (status %d)\n", job->jid, pid, WEXITSTATUS(status)); } deletejob(jobs,pid); } if(verbose) printf("sigchld_handler: exiting\n"); return; }