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;

Reply via email to