From patchwork Fri Apr 10 11:03:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herbert Xu X-Patchwork-Id: 11483143 X-Patchwork-Delegate: herbert@gondor.apana.org.au Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2A2E61871 for ; Fri, 10 Apr 2020 11:03:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0978B2078E for ; Fri, 10 Apr 2020 11:03:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726181AbgDJLDM (ORCPT ); Fri, 10 Apr 2020 07:03:12 -0400 Received: from helcar.hmeau.com ([216.24.177.18]:48170 "EHLO fornost.hmeau.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725930AbgDJLDM (ORCPT ); Fri, 10 Apr 2020 07:03:12 -0400 Received: from gwarestrin.me.apana.org.au ([192.168.0.7] helo=gwarestrin.arnor.me.apana.org.au) by fornost.hmeau.com with smtp (Exim 4.89 #2 (Debian)) id 1jMrRG-0008Q7-6l; Fri, 10 Apr 2020 21:03:11 +1000 Received: by gwarestrin.arnor.me.apana.org.au (sSMTP sendmail emulation); Fri, 10 Apr 2020 21:03:09 +1000 Date: Fri, 10 Apr 2020 21:03:09 +1000 From: Herbert Xu To: dash@vger.kernel.org, Harald van Dijk Subject: jobs: Fix infinite loop in waitproc Message-ID: <20200410110309.GA13801@gondor.apana.org.au> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) Sender: dash-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: dash@vger.kernel.org After we changed the resetting of gotsigchld so that it is only done if jp is NULL, we can now get an infinite loop in waitproc if gotsigchld is set but there is no outstanding child because everything had been waited for previously without gotsigchld being zeroed. This patch fixes it by always zeroing gotsigchld as we did before. The bug that the previous patch was trying to fix is now resolved by switching the blocking mode to DOWAIT_NORMAL after the specified job has been completed so that we really do wait for all outstanding dead children. Reported-by: Harald van Dijk Fixes: 6c691b3e5099 ("jobs: Only clear gotsigchld when waiting...") Signed-off-by: Herbert Xu diff --git a/src/jobs.c b/src/jobs.c index 26a6248..72e7aa9 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -1123,15 +1123,28 @@ out: static int dowait(int block, struct job *jp) { - int pid = block == DOWAIT_NORMAL ? gotsigchld : 1; + int gotchld = *(volatile int *)&gotsigchld; + int rpid; + int pid; + + if (jp && jp->state != JOBRUNNING) + block = DOWAIT_NORMAL; + + if (block == DOWAIT_NORMAL && !gotchld) + return 1; - while (jp ? jp->state == JOBRUNNING : pid > 0) { - if (!jp) - gotsigchld = 0; + rpid = 1; + + do { + gotsigchld = 0; pid = waitone(block, jp); - } + rpid &= !!pid; - return pid; + if (!pid || (jp && jp->state != JOBRUNNING)) + block = DOWAIT_NORMAL; + } while (pid >= 0); + + return rpid; } /* @@ -1163,7 +1176,10 @@ waitproc(int block, int *status) #endif do { - err = wait3(status, flags, NULL); + do + err = wait3(status, flags, NULL); + while (err < 0 && errno == EINTR); + if (err || (err = -!block)) break; @@ -1173,8 +1189,6 @@ waitproc(int block, int *status) sigsuspend(&oldmask); sigclearmask(); - - err = 0; } while (gotsigchld); return err;