Simon J. Gerraty <s...@juniper.net> wrote: > There's a gratuitous call to Job_CatchChildren in Job_CatchOutput. > > It should probbaly suffice to call Job_CatchChildren after a SIGCHLD. > It is a common misstake to assume that SIGCHLD will be receieved for each > child - which is why looping in Job_CatchChildren is important. > This means there will always be a wasted waitpid per call to > Job_CatchChildren.
The following is a minimal patch that should mitigate the waitpid calls suggestions for better names welcome. diff -r 51f1c026fe8f bmake/job.c --- a/bmake/job.c Sun Jan 24 19:26:00 2021 -0800 +++ b/bmake/job.c Fri Jan 29 15:07:48 2021 -0800 @@ -452,6 +452,7 @@ }; static sigset_t caught_signals; /* Set of signals we handle */ +static volatile int reap_children; static void JobDoOutput(Job *, Boolean); static void JobInterrupt(Boolean, int) MAKE_ATTR_DEAD; @@ -616,6 +617,7 @@ static void JobChildSig(int signo MAKE_ATTR_UNUSED) { + reap_children = 1; while (write(childExitJob.outPipe, CHILD_EXIT, 1) == -1 && errno == EAGAIN) continue; @@ -1992,7 +1994,9 @@ /* Don't even bother if we know there's no one around. */ if (jobTokensRunning == 0) return; - + if (reap_children == 0) + return; + reap_children = 0; while ((pid = waitpid((pid_t)-1, &status, WNOHANG | WUNTRACED)) > 0) { DEBUG2(JOB, "Process %d exited/stopped status %x.\n", pid, WAIT_STATUS(status)); @@ -2227,6 +2231,7 @@ memset(job_table, 0, (size_t)opts.maxJobs * sizeof *job_table); job_table_end = job_table + opts.maxJobs; wantToken = 0; + reap_children = 0; aborting = ABORT_NONE; job_errors = 0;