aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-11-03 20:17:23 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2016-11-03 20:22:54 +0100
commit1ab7c2fc6daf252f20d17949e70829905a7fd72a (patch)
tree73f06aa0de7ec8c11c81f00a36273ce1940cff87
parent2e6af549715f5d7b4c2ab204e46c8b8f6f057045 (diff)
downloadbusybox-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.c11
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) {