ash: use pause(), not sigsuspend(), in wait builtin
Same effect, smaller code function old new delta dowait 463 374 -89 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
d81e9f5093
commit
8f7b0248ad
57
shell/ash.c
57
shell/ash.c
@ -296,8 +296,7 @@ struct globals_misc {
|
||||
volatile int suppress_int; /* counter */
|
||||
volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */
|
||||
volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */
|
||||
/* last pending signal */
|
||||
volatile /*sig_atomic_t*/ smallint pending_sig;
|
||||
volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */
|
||||
smallint exception_type; /* kind of exception (0..5) */
|
||||
/* exceptions */
|
||||
#define EXINT 0 /* SIGINT received */
|
||||
@ -3515,11 +3514,6 @@ setsignal(int signo)
|
||||
#define CUR_RUNNING 1
|
||||
#define CUR_STOPPED 0
|
||||
|
||||
/* mode flags for dowait */
|
||||
#define DOWAIT_NONBLOCK 0
|
||||
#define DOWAIT_BLOCK 1
|
||||
#define DOWAIT_BLOCK_OR_SIG 2
|
||||
|
||||
#if JOBS
|
||||
/* pgrp of shell on invocation */
|
||||
static int initialpgrp; //references:2
|
||||
@ -3940,24 +3934,30 @@ sprint_status48(char *s, int status, int sigonly)
|
||||
}
|
||||
|
||||
static int
|
||||
wait_block_or_sig(int *status, int wait_flags)
|
||||
wait_block_or_sig(int *status)
|
||||
{
|
||||
sigset_t mask;
|
||||
int pid;
|
||||
|
||||
do {
|
||||
/* Poll all children for changes in their state */
|
||||
got_sigchld = 0;
|
||||
pid = waitpid(-1, status, wait_flags | WNOHANG);
|
||||
/* if job control is active, accept stopped processes too */
|
||||
pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
|
||||
if (pid != 0)
|
||||
break; /* Error (e.g. EINTR) or pid */
|
||||
break; /* Error (e.g. EINTR, ECHILD) or pid */
|
||||
|
||||
/* No child is ready. Sleep until interesting signal is received */
|
||||
/* Children exist, but none are ready. Sleep until interesting signal */
|
||||
#if 0 /* dash does this */
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, &mask);
|
||||
while (!got_sigchld && !pending_sig)
|
||||
sigsuspend(&mask);
|
||||
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
#else
|
||||
while (!got_sigchld && !pending_sig)
|
||||
pause();
|
||||
#endif
|
||||
|
||||
/* If it was SIGCHLD, poll children again */
|
||||
} while (got_sigchld);
|
||||
@ -3965,11 +3965,13 @@ wait_block_or_sig(int *status, int wait_flags)
|
||||
return pid;
|
||||
}
|
||||
|
||||
#define DOWAIT_NONBLOCK 0
|
||||
#define DOWAIT_BLOCK 1
|
||||
#define DOWAIT_BLOCK_OR_SIG 2
|
||||
|
||||
static int
|
||||
dowait(int block, struct job *job)
|
||||
{
|
||||
int wait_flags;
|
||||
int pid;
|
||||
int status;
|
||||
struct job *jp;
|
||||
@ -3977,13 +3979,6 @@ dowait(int block, struct job *job)
|
||||
|
||||
TRACE(("dowait(0x%x) called\n", block));
|
||||
|
||||
wait_flags = 0;
|
||||
if (block == DOWAIT_NONBLOCK)
|
||||
wait_flags = WNOHANG;
|
||||
/* If job control is compiled in, we accept stopped processes too. */
|
||||
if (doing_jobctl)
|
||||
wait_flags |= WUNTRACED;
|
||||
|
||||
/* It's wrong to call waitpid() outside of INT_OFF region:
|
||||
* signal can arrive just after syscall return and handler can
|
||||
* longjmp away, losing stop/exit notification processing.
|
||||
@ -3994,17 +3989,27 @@ dowait(int block, struct job *job)
|
||||
* in INT_OFF region: "wait" needs to wait for any running job
|
||||
* to change state, but should exit on any trap too.
|
||||
* In INT_OFF region, a signal just before syscall entry can set
|
||||
* pending_sig valiables, but we can't check them, and we would
|
||||
* pending_sig variables, but we can't check them, and we would
|
||||
* 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 sigsuspend().
|
||||
* which combines waitpid() and pause().
|
||||
* This is the reason why we need to have a handler for SIGCHLD:
|
||||
* SIG_DFL handler does not wake pause().
|
||||
*/
|
||||
INT_OFF;
|
||||
if (block == DOWAIT_BLOCK_OR_SIG)
|
||||
pid = wait_block_or_sig(&status, wait_flags);
|
||||
else
|
||||
/* NB: _not_ safe_waitpid, we need to detect EINTR. */
|
||||
if (block == DOWAIT_BLOCK_OR_SIG) {
|
||||
pid = wait_block_or_sig(&status);
|
||||
} else {
|
||||
int wait_flags = 0;
|
||||
if (block == DOWAIT_NONBLOCK)
|
||||
wait_flags = WNOHANG;
|
||||
/* if job control is active, accept stopped processes too */
|
||||
if (doing_jobctl)
|
||||
wait_flags |= WUNTRACED;
|
||||
/* NB: _not_ safe_waitpid, we need to detect EINTR */
|
||||
pid = waitpid(-1, &status, wait_flags);
|
||||
}
|
||||
TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
|
||||
pid, status, errno, strerror(errno)));
|
||||
if (pid <= 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user