[git commit] ash: jobs - Do not block when waiting on SIGCHLD

Denys Vlasenko vda.linux at googlemail.com
Tue Feb 18 14:37:22 UTC 2020


commit: https://git.busybox.net/busybox/commit/?id=97edfc42f112a15828aaec886ef7012d24f34d5e
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Upstream comment:

    Date: Mon, 7 May 2018 00:40:34 +0800
    jobs - Do not block when waiting on SIGCHLD

    Because of the nature of SIGCHLD, the process may have already been
    waited on and therefore we must be prepared for the case that wait
    may block.  So ensure that it doesn't by using WNOHANG.

    Furthermore, multiple jobs may have exited when gotsigchld is set.
    Therefore we need to wait until there are no zombies left.

    Lastly, waitforjob needs to be called with interrupts off and
    the original patch broke that.

    Fixes: 03876c0743a5 ("eval: Reap zombies after built-in...")
    Signed-off-by: Herbert Xu <herbert at gondor.apana.org.au>

While at it, removed INT_ON/OFF in waitforjob() - it must be called
from INT_OFF region anyway.

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/ash.c | 25 ++++++++++++++-----------
 1 file changed, 14 insertions(+), 11 deletions(-)

diff --git a/shell/ash.c b/shell/ash.c
index 8047cf98f..2b1378694 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -5357,8 +5357,16 @@ waitforjob(struct job *jp)
 
 	TRACE(("waitforjob(%%%d) called\n", jp ? jobno(jp) : 0));
 
-	INT_OFF;
-	while ((jp && jp->state == JOBRUNNING) || got_sigchld) {
+	if (!jp) {
+		int pid = got_sigchld;
+
+		while (pid > 0)
+			pid = dowait(DOWAIT_NONBLOCK, NULL);
+
+		return exitstatus;
+	}
+
+	while (jp->state == JOBRUNNING) {
 		/* In non-interactive shells, we _can_ get
 		 * a keyboard signal here and be EINTRed,
 		 * but we just loop back, waiting for command to complete.
@@ -5391,10 +5399,7 @@ waitforjob(struct job *jp)
 		 */
 		dowait(DOWAIT_BLOCK, jp);
 	}
-	INT_ON;
 
-	if (!jp)
-		return exitstatus;
 	st = getstatus(jp);
 #if JOBS
 	if (jp->jobctl) {
@@ -10369,7 +10374,6 @@ evalcommand(union node *cmd, int flags)
 			jp = makejob(/*cmd,*/ 1);
 			if (forkshell(jp, cmd, FORK_FG) != 0) {
 				/* parent */
-				INT_ON;
 				TRACE(("forked child exited with %d\n", status));
 				break;
 			}
@@ -10387,11 +10391,9 @@ evalcommand(union node *cmd, int flags)
 			if (cmd_is_exec && argc > 1)
 				listsetvar(varlist.list, VEXPORT);
 		}
-		if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
-			if (exception_type == EXERROR && spclbltin <= 0) {
-				FORCE_INT_ON;
-				break;
-			}
+		if (evalbltin(cmdentry.u.cmd, argc, argv, flags)
+		 && !(exception_type == EXERROR && spclbltin <= 0)
+		) {
  raise:
 			longjmp(exception_handler->loc, 1);
 		}
@@ -10404,6 +10406,7 @@ evalcommand(union node *cmd, int flags)
 	} /* switch */
 
 	status = waitforjob(jp);
+	FORCE_INT_ON;
 
  out:
 	if (cmd->ncmd.redirect)


More information about the busybox-cvs mailing list