ash: while (!got_sig) pause() is not reliable, use sigsuspend()
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 3 Nov 2016 19:17:23 +0000 (20:17 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 3 Nov 2016 19:22:54 +0000 (20:22 +0100)
dash was doing it for a reason. Unfortunately, it had no comment why...
now I know.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c

index ecd2146e462592329676c303def614fb01f4b90c..f756428688cdeb055453aa5b6768aed2e1918393 100644 (file)
@@ -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) {