diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-03 22:17:23 +0300 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-03 22:22:54 +0300 |
commit | 1ab7c2fc6daf252f20d17949e70829905a7fd72a (patch) | |
tree | 73f06aa0de7ec8c11c81f00a36273ce1940cff87 /shell/ash.c | |
parent | 2e6af549715f5d7b4c2ab204e46c8b8f6f057045 (diff) |
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>
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/shell/ash.c b/shell/ash.c index ecd2146e4..f75642868 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) { |