computer-system/CMU15-213/labs/LAB5_tshlab/tsh.c
void sigchld_handler(int sig) {
    int olderrno = errno;
    sigset_t mask_all, prev_all;
    Sigfillset(&mask_all);
    
    pid_t pid;
    int status, jid;
    while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
        if(WIFEXITED(status)) {             
            /* Exited normally */
            Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
            deletejob(jobs, pid);
            Sigprocmask(SIG_SETMASK, &prev_all, NULL);
        } else if(WIFSTOPPED(status)) {     
            /* SIGTSTP & SIGSTOP */
            Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
            struct job_t *job_to_stop = getjobpid(jobs, pid);
            job_to_stop -> state = ST;

            Sio_puts("Job [");
            Sio_putl(pid2jid(pid));
            Sio_puts("] (");
            Sio_putl(pid);
            Sio_puts(") stopped by signal 20\n");
            Sigprocmask(SIG_SETMASK, &prev_all, NULL);
        } else if(WIFSIGNALED(status)) {    
            /* Terminated with signal didn't catch */
            Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
            jid = pid2jid(pid);
            deletejob(jobs, pid);
            Sigprocmask(SIG_SETMASK, &prev_all, NULL);

            Sio_puts("Job [");
            Sio_putl(jid);
            Sio_puts("] (");
            Sio_putl(pid);
            Sio_puts(") terminated by signal ");
            Sio_putl(WTERMSIG(status));
            Sio_puts("\n");
        } else {                            
            /* You won't actually get here */
            assert(0);
        }
    }

    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.  
 */
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.
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;
    Sigfillset(&mask_all);
    pid_t pid;
    int status, jid;
    while((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
        if(WIFEXITED(status)) {             
            Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
            deletejob(jobs, pid);
            Sigprocmask(SIG_SETMASK, &prev_all, NULL);
        } else if(WIFSTOPPED(status)) {     
            Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
            struct job_t *job_to_stop = getjobpid(jobs, pid);
            job_to_stop -> state = ST;
            Sio_puts("Job [");
            Sio_putl(pid2jid(pid));
            Sio_puts("] (");
            Sio_putl(pid);
            Sio_puts(") stopped by signal 20\n");
            Sigprocmask(SIG_SETMASK, &prev_all, NULL);
        } else if(WIFSIGNALED(status)) {    
            Sigprocmask(SIG_BLOCK, &mask_all, &prev_all);
            jid = pid2jid(pid);
            deletejob(jobs, pid);
            Sigprocmask(SIG_SETMASK, &prev_all, NULL);
            Sio_puts("Job [");
            Sio_putl(jid);
            Sio_puts("] (");
            Sio_putl(pid);
            Sio_puts(") terminated by signal ");
            Sio_putl(WTERMSIG(status));
            Sio_puts("\n");
        } else {                            
            assert(0);
        }
    }
    errno = olderrno;
    return;
}
void sigchld_handler ( int sig ) { int olderrno = errno ; sigset_t mask_all , prev_all ; Sigfillset ( & mask_all ) ; pid_t pid ; int status , jid ; while ( ( pid = waitpid ( -1 , & status , WNOHANG | WUNTRACED ) ) > 0 ) { if ( WIFEXITED ( status ) ) { Sigprocmask ( SIG_BLOCK , & mask_all , & prev_all ) ; deletejob ( jobs , pid ) ; Sigprocmask ( SIG_SETMASK , & prev_all , NULL ) ; } else if ( WIFSTOPPED ( status ) ) { Sigprocmask ( SIG_BLOCK , & mask_all , & prev_all ) ; struct job_t * job_to_stop = getjobpid ( jobs , pid ) ; job_to_stop -> state = ST ; Sio_puts ( " " ) ; Sio_putl ( pid2jid ( pid ) ) ; Sio_puts ( " " ) ; Sio_putl ( pid ) ; Sio_puts ( " \n " ) ; Sigprocmask ( SIG_SETMASK , & prev_all , NULL ) ; } else if ( WIFSIGNALED ( status ) ) { Sigprocmask ( SIG_BLOCK , & mask_all , & prev_all ) ; jid = pid2jid ( pid ) ; deletejob ( jobs , pid ) ; Sigprocmask ( SIG_SETMASK , & prev_all , NULL ) ; Sio_puts ( " " ) ; Sio_putl ( jid ) ; Sio_puts ( " " ) ; Sio_putl ( pid ) ; Sio_puts ( " " ) ; Sio_putl ( WTERMSIG ( status ) ) ; Sio_puts ( " \n " ) ; } else { assert ( 0 ) ; } } 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.
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 .
/* Exited normally */ /* SIGTSTP & SIGSTOP */ /* Terminated with signal didn't catch */ /* You won't actually get here */