diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-28 17:16:11 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-28 17:16:11 +0200 |
commit | 8f7b0248adca9a88351fd7f3dd208775242f3fe6 (patch) | |
tree | 813260e706183bee2bd28902587c4e1a7090a615 | |
parent | d81e9f5093b222369d510d0b1c0587a411e4c83e (diff) | |
download | busybox-w32-8f7b0248adca9a88351fd7f3dd208775242f3fe6.tar.gz busybox-w32-8f7b0248adca9a88351fd7f3dd208775242f3fe6.tar.bz2 busybox-w32-8f7b0248adca9a88351fd7f3dd208775242f3fe6.zip |
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>
-rw-r--r-- | shell/ash.c | 57 |
1 files changed, 31 insertions, 26 deletions
diff --git a/shell/ash.c b/shell/ash.c index fe112453c..fc1b5d927 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -296,8 +296,7 @@ struct globals_misc { | |||
296 | volatile int suppress_int; /* counter */ | 296 | volatile int suppress_int; /* counter */ |
297 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ | 297 | volatile /*sig_atomic_t*/ smallint pending_int; /* 1 = got SIGINT */ |
298 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ | 298 | volatile /*sig_atomic_t*/ smallint got_sigchld; /* 1 = got SIGCHLD */ |
299 | /* last pending signal */ | 299 | volatile /*sig_atomic_t*/ smallint pending_sig; /* last pending signal */ |
300 | volatile /*sig_atomic_t*/ smallint pending_sig; | ||
301 | smallint exception_type; /* kind of exception (0..5) */ | 300 | smallint exception_type; /* kind of exception (0..5) */ |
302 | /* exceptions */ | 301 | /* exceptions */ |
303 | #define EXINT 0 /* SIGINT received */ | 302 | #define EXINT 0 /* SIGINT received */ |
@@ -3515,11 +3514,6 @@ setsignal(int signo) | |||
3515 | #define CUR_RUNNING 1 | 3514 | #define CUR_RUNNING 1 |
3516 | #define CUR_STOPPED 0 | 3515 | #define CUR_STOPPED 0 |
3517 | 3516 | ||
3518 | /* mode flags for dowait */ | ||
3519 | #define DOWAIT_NONBLOCK 0 | ||
3520 | #define DOWAIT_BLOCK 1 | ||
3521 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
3522 | |||
3523 | #if JOBS | 3517 | #if JOBS |
3524 | /* pgrp of shell on invocation */ | 3518 | /* pgrp of shell on invocation */ |
3525 | static int initialpgrp; //references:2 | 3519 | static int initialpgrp; //references:2 |
@@ -3940,24 +3934,30 @@ sprint_status48(char *s, int status, int sigonly) | |||
3940 | } | 3934 | } |
3941 | 3935 | ||
3942 | static int | 3936 | static int |
3943 | wait_block_or_sig(int *status, int wait_flags) | 3937 | wait_block_or_sig(int *status) |
3944 | { | 3938 | { |
3945 | sigset_t mask; | ||
3946 | int pid; | 3939 | int pid; |
3947 | 3940 | ||
3948 | do { | 3941 | do { |
3949 | /* Poll all children for changes in their state */ | 3942 | /* Poll all children for changes in their state */ |
3950 | got_sigchld = 0; | 3943 | got_sigchld = 0; |
3951 | pid = waitpid(-1, status, wait_flags | WNOHANG); | 3944 | /* if job control is active, accept stopped processes too */ |
3945 | pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG); | ||
3952 | if (pid != 0) | 3946 | if (pid != 0) |
3953 | break; /* Error (e.g. EINTR) or pid */ | 3947 | break; /* Error (e.g. EINTR, ECHILD) or pid */ |
3954 | 3948 | ||
3955 | /* No child is ready. Sleep until interesting signal is received */ | 3949 | /* Children exist, but none are ready. Sleep until interesting signal */ |
3950 | #if 0 /* dash does this */ | ||
3951 | sigset_t mask; | ||
3956 | sigfillset(&mask); | 3952 | sigfillset(&mask); |
3957 | sigprocmask(SIG_SETMASK, &mask, &mask); | 3953 | sigprocmask(SIG_SETMASK, &mask, &mask); |
3958 | while (!got_sigchld && !pending_sig) | 3954 | while (!got_sigchld && !pending_sig) |
3959 | sigsuspend(&mask); | 3955 | sigsuspend(&mask); |
3960 | sigprocmask(SIG_SETMASK, &mask, NULL); | 3956 | sigprocmask(SIG_SETMASK, &mask, NULL); |
3957 | #else | ||
3958 | while (!got_sigchld && !pending_sig) | ||
3959 | pause(); | ||
3960 | #endif | ||
3961 | 3961 | ||
3962 | /* If it was SIGCHLD, poll children again */ | 3962 | /* If it was SIGCHLD, poll children again */ |
3963 | } while (got_sigchld); | 3963 | } while (got_sigchld); |
@@ -3965,11 +3965,13 @@ wait_block_or_sig(int *status, int wait_flags) | |||
3965 | return pid; | 3965 | return pid; |
3966 | } | 3966 | } |
3967 | 3967 | ||
3968 | #define DOWAIT_NONBLOCK 0 | ||
3969 | #define DOWAIT_BLOCK 1 | ||
3970 | #define DOWAIT_BLOCK_OR_SIG 2 | ||
3968 | 3971 | ||
3969 | static int | 3972 | static int |
3970 | dowait(int block, struct job *job) | 3973 | dowait(int block, struct job *job) |
3971 | { | 3974 | { |
3972 | int wait_flags; | ||
3973 | int pid; | 3975 | int pid; |
3974 | int status; | 3976 | int status; |
3975 | struct job *jp; | 3977 | struct job *jp; |
@@ -3977,13 +3979,6 @@ dowait(int block, struct job *job) | |||
3977 | 3979 | ||
3978 | TRACE(("dowait(0x%x) called\n", block)); | 3980 | TRACE(("dowait(0x%x) called\n", block)); |
3979 | 3981 | ||
3980 | wait_flags = 0; | ||
3981 | if (block == DOWAIT_NONBLOCK) | ||
3982 | wait_flags = WNOHANG; | ||
3983 | /* If job control is compiled in, we accept stopped processes too. */ | ||
3984 | if (doing_jobctl) | ||
3985 | wait_flags |= WUNTRACED; | ||
3986 | |||
3987 | /* It's wrong to call waitpid() outside of INT_OFF region: | 3982 | /* It's wrong to call waitpid() outside of INT_OFF region: |
3988 | * signal can arrive just after syscall return and handler can | 3983 | * signal can arrive just after syscall return and handler can |
3989 | * longjmp away, losing stop/exit notification processing. | 3984 | * longjmp away, losing stop/exit notification processing. |
@@ -3994,17 +3989,27 @@ dowait(int block, struct job *job) | |||
3994 | * in INT_OFF region: "wait" needs to wait for any running job | 3989 | * in INT_OFF region: "wait" needs to wait for any running job |
3995 | * to change state, but should exit on any trap too. | 3990 | * to change state, but should exit on any trap too. |
3996 | * In INT_OFF region, a signal just before syscall entry can set | 3991 | * In INT_OFF region, a signal just before syscall entry can set |
3997 | * pending_sig valiables, but we can't check them, and we would | 3992 | * pending_sig variables, but we can't check them, and we would |
3998 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. | 3993 | * either enter a sleeping waitpid() (BUG), or need to busy-loop. |
3994 | * | ||
3999 | * Because of this, we run inside INT_OFF, but use a special routine | 3995 | * Because of this, we run inside INT_OFF, but use a special routine |
4000 | * which combines waitpid() and sigsuspend(). | 3996 | * which combines waitpid() and pause(). |
3997 | * This is the reason why we need to have a handler for SIGCHLD: | ||
3998 | * SIG_DFL handler does not wake pause(). | ||
4001 | */ | 3999 | */ |
4002 | INT_OFF; | 4000 | INT_OFF; |
4003 | if (block == DOWAIT_BLOCK_OR_SIG) | 4001 | if (block == DOWAIT_BLOCK_OR_SIG) { |
4004 | pid = wait_block_or_sig(&status, wait_flags); | 4002 | pid = wait_block_or_sig(&status); |
4005 | else | 4003 | } else { |
4006 | /* NB: _not_ safe_waitpid, we need to detect EINTR. */ | 4004 | int wait_flags = 0; |
4005 | if (block == DOWAIT_NONBLOCK) | ||
4006 | wait_flags = WNOHANG; | ||
4007 | /* if job control is active, accept stopped processes too */ | ||
4008 | if (doing_jobctl) | ||
4009 | wait_flags |= WUNTRACED; | ||
4010 | /* NB: _not_ safe_waitpid, we need to detect EINTR */ | ||
4007 | pid = waitpid(-1, &status, wait_flags); | 4011 | pid = waitpid(-1, &status, wait_flags); |
4012 | } | ||
4008 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", | 4013 | TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", |
4009 | pid, status, errno, strerror(errno))); | 4014 | pid, status, errno, strerror(errno))); |
4010 | if (pid <= 0) | 4015 | if (pid <= 0) |