diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-03 20:17:23 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-03 20:22:54 +0100 |
commit | 1ab7c2fc6daf252f20d17949e70829905a7fd72a (patch) | |
tree | 73f06aa0de7ec8c11c81f00a36273ce1940cff87 | |
parent | 2e6af549715f5d7b4c2ab204e46c8b8f6f057045 (diff) | |
download | busybox-w32-1ab7c2fc6daf252f20d17949e70829905a7fd72a.tar.gz busybox-w32-1ab7c2fc6daf252f20d17949e70829905a7fd72a.tar.bz2 busybox-w32-1ab7c2fc6daf252f20d17949e70829905a7fd72a.zip |
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>
-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) | |||
3933 | int pid; | 3933 | int pid; |
3934 | 3934 | ||
3935 | do { | 3935 | do { |
3936 | sigset_t mask; | ||
3937 | |||
3936 | /* Poll all children for changes in their state */ | 3938 | /* Poll all children for changes in their state */ |
3937 | got_sigchld = 0; | 3939 | got_sigchld = 0; |
3938 | /* if job control is active, accept stopped processes too */ | 3940 | /* if job control is active, accept stopped processes too */ |
@@ -3941,14 +3943,13 @@ wait_block_or_sig(int *status) | |||
3941 | break; /* Error (e.g. EINTR, ECHILD) or pid */ | 3943 | break; /* Error (e.g. EINTR, ECHILD) or pid */ |
3942 | 3944 | ||
3943 | /* Children exist, but none are ready. Sleep until interesting signal */ | 3945 | /* Children exist, but none are ready. Sleep until interesting signal */ |
3944 | #if 0 /* dash does this */ | 3946 | #if 1 |
3945 | sigset_t mask; | ||
3946 | sigfillset(&mask); | 3947 | sigfillset(&mask); |
3947 | sigprocmask(SIG_SETMASK, &mask, &mask); | 3948 | sigprocmask(SIG_SETMASK, &mask, &mask); |
3948 | while (!got_sigchld && !pending_sig) | 3949 | while (!got_sigchld && !pending_sig) |
3949 | sigsuspend(&mask); | 3950 | sigsuspend(&mask); |
3950 | sigprocmask(SIG_SETMASK, &mask, NULL); | 3951 | sigprocmask(SIG_SETMASK, &mask, NULL); |
3951 | #else | 3952 | #else /* unsafe: a signal can set pending_sig after check, but before pause() */ |
3952 | while (!got_sigchld && !pending_sig) | 3953 | while (!got_sigchld && !pending_sig) |
3953 | pause(); | 3954 | pause(); |
3954 | #endif | 3955 | #endif |
@@ -3987,9 +3988,9 @@ dowait(int block, struct job *job) | |||
3987 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. | 3988 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. |
3988 | * | 3989 | * |
3989 | * Because of this, we run inside INT_OFF, but use a special routine | 3990 | * Because of this, we run inside INT_OFF, but use a special routine |
3990 | * which combines waitpid() and pause(). | 3991 | * which combines waitpid() and sigsuspend(). |
3991 | * This is the reason why we need to have a handler for SIGCHLD: | 3992 | * This is the reason why we need to have a handler for SIGCHLD: |
3992 | * SIG_DFL handler does not wake pause(). | 3993 | * SIG_DFL handler does not wake sigsuspend(). |
3993 | */ | 3994 | */ |
3994 | INT_OFF; | 3995 | INT_OFF; |
3995 | if (block == DOWAIT_BLOCK_OR_SIG) { | 3996 | if (block == DOWAIT_BLOCK_OR_SIG) { |