ast_comparator/test/student_data/handout/shlab-handout/cases/53_tsh.c
/*
  * 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)
{
	pid_t child_pid;
	int child_status;
	while (true)
	{
		child_pid = waitpid(-1, &child_status, WNOHANG | WUNTRACED | WCONTINUED);
		if (child_pid == 0)
			break;
		else if (child_pid == -1)
		{
			if (errno == ECHILD)
				break;
			else
				unix_error("waitpid failed");
		}
		struct job_t *job = get_job_by_pid(jobs, child_pid);
		if (WIFEXITED(child_status)) 
			delete_job_by_job_t(jobs, job);
		else if (WIFSIGNALED(child_status)) 
		{
			printf("Job [%d] (%d) terminated by signal %d\n", job->jid, job->pid, WTERMSIG(child_status));
			delete_job_by_job_t(jobs, job);
		}
		else if (WIFSTOPPED(child_status)) 
		{
			printf("Job [%d] (%d) stopped by signal %d\n", job->jid, job->pid, WSTOPSIG(child_status));
			job->state = STATE_STOPPED;
		}
		else if (WIFCONTINUED(child_status)) 
		{
			if (job->state == STATE_FOREGROUND)
				continue;
			else
				job->state = STATE_BACKGROUND;
		}
		else
		{
			fprintf(stderr, "Untreated status %d from child %d\n", child_status, child_pid);
			print_job_list(jobs);
			exit(1);
		}
	}
}
void sigchld_handler ( int sig ) { pid_t child_pid ; int child_status ; while ( true ) { child_pid = waitpid ( -1 , & child_status , WNOHANG | WUNTRACED | WCONTINUED ) ; if ( child_pid == 0 ) break ; else if ( child_pid == -1 ) { if ( errno == ECHILD ) break ; else unix_error ( " " ) ; } struct job_t * job = get_job_by_pid ( jobs , child_pid ) ; if ( WIFEXITED ( child_status ) ) delete_job_by_job_t ( jobs , job ) ; else if ( WIFSIGNALED ( child_status ) ) { printf ( " \n " , job -> jid , job -> pid , WTERMSIG ( child_status ) ) ; delete_job_by_job_t ( jobs , job ) ; } else if ( WIFSTOPPED ( child_status ) ) { printf ( " \n " , job -> jid , job -> pid , WSTOPSIG ( child_status ) ) ; job -> state = STATE_STOPPED ; } else if ( WIFCONTINUED ( child_status ) ) { if ( job -> state == STATE_FOREGROUND ) continue ; else job -> state = STATE_BACKGROUND ; } else { fprintf ( stderr , " \n " , child_status , child_pid ) ; print_job_list ( jobs ) ; exit ( 1 ) ; } } }
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 .
// Child is exited // Child is terminated by signal // Child is stopped // Child is continued // Do nothing if child is continued by fg command // If child is continued by bg command or signal from outside