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:
11
shell/ash.c
11
shell/ash.c
@@ -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) {
|
||||||
|
Reference in New Issue
Block a user