ash: while (!got_sig) pause() is not reliable, use sigsuspend()

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>
This commit is contained in:
Denys Vlasenko
2016-11-03 20:17:23 +01:00
parent 2e6af54971
commit 1ab7c2fc6d

View File

@@ -3933,6 +3933,8 @@ wait_block_or_sig(int *status)
int pid; int pid;
do { do {
sigset_t mask;
/* Poll all children for changes in their state */ /* Poll all children for changes in their state */
got_sigchld = 0; got_sigchld = 0;
/* if job control is active, accept stopped processes too */ /* 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 */ break; /* Error (e.g. EINTR, ECHILD) or pid */
/* Children exist, but none are ready. Sleep until interesting signal */ /* Children exist, but none are ready. Sleep until interesting signal */
#if 0 /* dash does this */ #if 1
sigset_t mask;
sigfillset(&mask); sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, &mask); sigprocmask(SIG_SETMASK, &mask, &mask);
while (!got_sigchld && !pending_sig) while (!got_sigchld && !pending_sig)
sigsuspend(&mask); sigsuspend(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL); sigprocmask(SIG_SETMASK, &mask, NULL);
#else #else /* unsafe: a signal can set pending_sig after check, but before pause() */
while (!got_sigchld && !pending_sig) while (!got_sigchld && !pending_sig)
pause(); pause();
#endif #endif
@@ -3987,9 +3988,9 @@ dowait(int block, struct job *job)
* either enter a sleeping waitpid() (BUG), or need to busy-loop. * either enter a sleeping waitpid() (BUG), or need to busy-loop.
* *
* Because of this, we run inside INT_OFF, but use a special routine * 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: * 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; INT_OFF;
if (block == DOWAIT_BLOCK_OR_SIG) { if (block == DOWAIT_BLOCK_OR_SIG) {