/* state change of children handled here */ static void sigchld_handler(int sig) { pid_t child_pid; jobs **job; int status; /* * There can be multiple SIGCHLD at once, not necessarily they will all be handled, * so we reap all the children in non-blocking mode that takes care of the pending child * whose SIGCHLD is not attended */ /* SIGCHLD should be blocked in critical section of modifying joblist */ /* thy shall NOT pass */ while ((child_pid = waitpid(-1, &status, WNOHANG|WUNTRACED|WCONTINUED)) > 0) { if (WIFEXITED(status)) { deljob(child_pid); } else if (WIFSIGNALED(status)) { job = getjob(child_pid, 0); if (NOTNULL(job)) { shell_printf(SHELLPRINT_CHKSS | SHELLPRINT_CHKTERM, TERMSTR_GREEN("SIGCHLD: ")"[%d] (%d) killed by signal %d\n", (*job)->jid, (*job)->pid[0], WTERMSIG(status)); deljob(child_pid); } } else if (WIFSTOPPED(status)) { job = getjob(child_pid, 0); if (NOTNULL(job)) { (*job)->state = ST; shell_printf(SHELLPRINT_CHKSS | SHELLPRINT_CHKTERM, TERMSTR_GREEN("SIGCHLD : ")"[%d] (%d) stopped by signal %d\n", (*job)->jid, (*job)->pid[0], WSTOPSIG(status)); } } else if (WIFCONTINUED(status)) { job = getjob(child_pid, 0); if (NOTNULL(job)) (*job)->state = BG; } } /* thy shall pass */ }
/* * the basic wait for foreground used by fg cmd and basic * non bg cmd in the shell. Make sure SIGCHLD is blocked * to avoid race conditions that make the joblist unreliable. * No terminal control or printing if subshell * */ void wait_fg(jobs **job) { int status, i; /* thy shall NOT pass */ for (i=0; NOTNULL(job); i++) { if (!subshell_flag && tcsetpgrp(TERMFD, (*job)->pid[0]) < 0) perror("tcsetpgrp"); while (waitpid((*job)->pid[i], &status, WUNTRACED) == 0) ; if (WIFEXITED(status)) { if (!subshell_flag && tcsetpgrp(TERMFD, getpid()) < 0) perror("tcsetpgrp"); if ((*job)->pid[i+1] == 0) { deljob((*job)->pid[0]); break; } } else if (WIFSIGNALED(status)) { if (!subshell_flag && tcsetpgrp(TERMFD, getpid()) < 0) perror("tcsetpgrp"); shell_printf(SHELLPRINT_CHKSS | SHELLPRINT_CHKTERM, "[%d] (%d) killed by signal %d\n", (*job)->jid, (*job)->pid[0], WTERMSIG(status)); deljob((*job)->pid[0]); break; } else if (WIFSTOPPED(status)) { if (!subshell_flag && tcsetpgrp(TERMFD, getpid()) < 0) perror("tcsetpgrp"); shell_printf(SHELLPRINT_CHKSS | SHELLPRINT_CHKTERM, "[%d] (%d) stopped by signal %d\n", (*job)->jid, (*job)->pid[0], WSTOPSIG(status)); (*job)->state = ST; break; } } /* thy shall pass */ }
STATIC void freejob(struct job *jp) { struct procstat *ps; int i; INTOFF; for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { if (ps->cmd != nullstr) ckfree(ps->cmd); } if (jp->ps != &jp->ps0) ckfree(jp->ps); jp->used = 0; #if JOBS deljob(jp); #endif INTON; }