[git commit] ash: while (!got_sig) pause() is not reliable, use sigsuspend()

Denys Vlasenko vda.linux at googlemail.com
Thu Nov 3 19:22:54 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=1ab7c2fc6daf252f20d17949e70829905a7fd72a
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

dash was doing it for a reason. Unfortunately, it had no comment why...
now I know.

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

diff --git a/shell/ash.c b/shell/ash.c
index ecd2146..f756428 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -3933,6 +3933,8 @@ wait_block_or_sig(int *status)
 	int pid;
 
 	do {
+		sigset_t mask;
+
 		/* Poll all children for changes in their state */
 		got_sigchld = 0;
 		/* if job control is active, accept stopped processes too */
@@ -3941,14 +3943,13 @@ wait_block_or_sig(int *status)
 			break; /* Error (e.g. EINTR, ECHILD) or pid */
 
 		/* Children exist, but none are ready. Sleep until interesting signal */
-#if 0 /* dash does this */
-		sigset_t mask;
+#if 1
 		sigfillset(&mask);
 		sigprocmask(SIG_SETMASK, &mask, &mask);
 		while (!got_sigchld && !pending_sig)
 			sigsuspend(&mask);
 		sigprocmask(SIG_SETMASK, &mask, NULL);
-#else
+#else /* unsafe: a signal can set pending_sig after check, but before pause() */
 		while (!got_sigchld && !pending_sig)
 			pause();
 #endif
@@ -3987,9 +3988,9 @@ dowait(int block, struct job *job)
 	 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
 	 *
 	 * Because of this, we run inside INT_OFF, but use a special routine
-	 * which combines waitpid() and pause().
+	 * which combines waitpid() and sigsuspend().
 	 * This is the reason why we need to have a handler for SIGCHLD:
-	 * SIG_DFL handler does not wake pause().
+	 * SIG_DFL handler does not wake sigsuspend().
 	 */
 	INT_OFF;
 	if (block == DOWAIT_BLOCK_OR_SIG) {


More information about the busybox-cvs mailing list