/* If we have received a SIGCHLD signal, process any children. If await is false, this returns immediately if no SIGCHLD has been received. If await is true, this waits for one. Returns true if something was processed. This returns the number of children processed, or -1 on error. */

staticintprocess_mark_finished_children(bool wants_await)

{

ASSERT_IS_MAIN_THREAD();

/* A static value tracking the SIGCHLD gen count at the time we last processed it. When this is different from s_sigchld_generation_count, it indicates there may be unreaped processes. There may not be if we reaped them via the other waitpid path. This is only ever modified from the main thread, and not from a signal handler. */

/* The critical read. This fetches a value which is only written in the signal handler. This needs to be an atomic read (we'd use sig_atomic_t, if we knew that were unsigned - fortunately aligned unsigned int is atomic on pretty much any modern chip.) It also needs to occur before we start reaping, since the signal handler can be invoked at any point. */

/* Determine whether we have children to process. Note that we can't reliably use the difference because a single SIGCHLD may be delivered for multiple children - see #1768. Also if we are awaiting, we always process. */

/* Call waitpid until we get 0/ECHILD. If we wait, it's only on the first iteration. So we want to set NOHANG (don't wait) unless wants_await is true and this is the first iteration. */

int options = WUNTRACED;

if (! (wants_await && processed_count == 0))

{

options |= WNOHANG;

}

int status = -1;

pid_t pid = waitpid(-1, &status, options);

if (pid > 0)

{

/* We got a valid pid */

handle_child_status(pid, status);

processed_count += 1;

}

elseif (pid == 0)

{

/* No ready-and-waiting children, we're done */

break;

}

else

{

/* This indicates an error. One likely failure is ECHILD (no children), which we break on, and is not considered an error. The other likely failure is EINTR, which means we got a signal, which is considered an error. */

got_error = (errno != ECHILD);

break;

}

}

}

if (got_error)

{

return -1;

}

else

{

s_last_processed_sigchld_generation_count = local_count;

return processed_count;

}

}

/* This is called from a signal handler. The signal is always SIGCHLD. */

voidjob_handle_signal(int signal, siginfo_t *info, void *con)

{

/* This is the only place that this generation count is modified. It's OK if it overflows. */

s_sigchld_generation_count += 1;

}

/* Given a command like "cat file", truncate it to a reasonable length */

/* Print nothing if we get SIGINT in the foreground process group, to avoid spamming obvious stuff on the console (#1119). If we get SIGINT for the foreground process, assume the user typed ^C and can see it working. It's possible they didn't, and the signal was delivered via pkill, etc., but the SIGINT/SIGTERM distinction is precisely to allow INT to be from a UI and TERM to be programmatic, so this assumption is keeping with the design of signals.

If echoctl is on, then the terminal will have written ^C to the console. If off, it won't have. We don't echo ^C either way, so as to respect the user's preference. */