aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--shell/ash.c83
1 files changed, 70 insertions, 13 deletions
diff --git a/shell/ash.c b/shell/ash.c
index b060d227a..1ef02b8be 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -295,6 +295,7 @@ struct globals_misc {
295 295
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 /* last pending signal */ 299 /* last pending signal */
299 volatile /*sig_atomic_t*/ smallint pending_sig; 300 volatile /*sig_atomic_t*/ smallint pending_sig;
300 smallint exception_type; /* kind of exception (0..5) */ 301 smallint exception_type; /* kind of exception (0..5) */
@@ -370,6 +371,7 @@ extern struct globals_misc *const ash_ptr_to_globals_misc;
370#define exception_type (G_misc.exception_type ) 371#define exception_type (G_misc.exception_type )
371#define suppress_int (G_misc.suppress_int ) 372#define suppress_int (G_misc.suppress_int )
372#define pending_int (G_misc.pending_int ) 373#define pending_int (G_misc.pending_int )
374#define got_sigchld (G_misc.got_sigchld )
373#define pending_sig (G_misc.pending_sig ) 375#define pending_sig (G_misc.pending_sig )
374#define isloginsh (G_misc.isloginsh ) 376#define isloginsh (G_misc.isloginsh )
375#define nullstr (G_misc.nullstr ) 377#define nullstr (G_misc.nullstr )
@@ -3388,7 +3390,14 @@ ignoresig(int signo)
3388static void 3390static void
3389signal_handler(int signo) 3391signal_handler(int signo)
3390{ 3392{
3393 if (signo == SIGCHLD) {
3394 got_sigchld = 1;
3395 if (!trap[SIGCHLD])
3396 return;
3397 }
3398
3391 gotsig[signo - 1] = 1; 3399 gotsig[signo - 1] = 1;
3400 pending_sig = signo;
3392 3401
3393 if (signo == SIGINT && !trap[SIGINT]) { 3402 if (signo == SIGINT && !trap[SIGINT]) {
3394 if (!suppress_int) { 3403 if (!suppress_int) {
@@ -3396,8 +3405,6 @@ signal_handler(int signo)
3396 raise_interrupt(); /* does not return */ 3405 raise_interrupt(); /* does not return */
3397 } 3406 }
3398 pending_int = 1; 3407 pending_int = 1;
3399 } else {
3400 pending_sig = signo;
3401 } 3408 }
3402} 3409}
3403 3410
@@ -3455,6 +3462,9 @@ setsignal(int signo)
3455//whereas we have to restore it to what shell got on entry 3462//whereas we have to restore it to what shell got on entry
3456//from the parent. See comment above 3463//from the parent. See comment above
3457 3464
3465 if (signo == SIGCHLD)
3466 new_act = S_CATCH;
3467
3458 t = &sigmode[signo - 1]; 3468 t = &sigmode[signo - 1];
3459 cur_act = *t; 3469 cur_act = *t;
3460 if (cur_act == 0) { 3470 if (cur_act == 0) {
@@ -3507,6 +3517,7 @@ setsignal(int signo)
3507/* mode flags for dowait */ 3517/* mode flags for dowait */
3508#define DOWAIT_NONBLOCK 0 3518#define DOWAIT_NONBLOCK 0
3509#define DOWAIT_BLOCK 1 3519#define DOWAIT_BLOCK 1
3520#define DOWAIT_BLOCK_OR_SIG 2
3510 3521
3511#if JOBS 3522#if JOBS
3512/* pgrp of shell on invocation */ 3523/* pgrp of shell on invocation */
@@ -3928,32 +3939,76 @@ sprint_status48(char *s, int status, int sigonly)
3928} 3939}
3929 3940
3930static int 3941static int
3942wait_block_or_sig(int *status, int wait_flags)
3943{
3944 sigset_t mask;
3945 int pid;
3946
3947 do {
3948 /* Poll all children for changes in their state */
3949 got_sigchld = 0;
3950 pid = waitpid(-1, status, wait_flags | WNOHANG);
3951 if (pid != 0)
3952 break; /* Error (e.g. EINTR) or pid */
3953
3954 /* No child is ready. Sleep until interesting signal is received */
3955 sigfillset(&mask);
3956 sigprocmask(SIG_SETMASK, &mask, &mask);
3957 while (!got_sigchld && !pending_sig)
3958 sigsuspend(&mask);
3959 sigprocmask(SIG_SETMASK, &mask, NULL);
3960
3961 /* If it was SIGCHLD, poll children again */
3962 } while (got_sigchld);
3963
3964 return pid;
3965}
3966
3967
3968static int
3931dowait(int block, struct job *job) 3969dowait(int block, struct job *job)
3932{ 3970{
3933 int wait_flags; 3971 int wait_flags;
3934 int pid; 3972 int pid;
3935 int status; 3973 int status;
3936 struct job *jp; 3974 struct job *jp;
3937 struct job *thisjob; 3975 struct job *thisjob = NULL;
3938 3976
3939 TRACE(("dowait(0x%x) called\n", block)); 3977 TRACE(("dowait(0x%x) called\n", block));
3940 3978
3941 /* Do a wait system call. If job control is compiled in, we accept
3942 * stopped processes.
3943 * NB: _not_ safe_waitpid, we need to detect EINTR.
3944 */
3945 wait_flags = 0; 3979 wait_flags = 0;
3946 if (block == DOWAIT_NONBLOCK) 3980 if (block == DOWAIT_NONBLOCK)
3947 wait_flags = WNOHANG; 3981 wait_flags = WNOHANG;
3982 /* If job control is compiled in, we accept stopped processes too. */
3948 if (doing_jobctl) 3983 if (doing_jobctl)
3949 wait_flags |= WUNTRACED; 3984 wait_flags |= WUNTRACED;
3950 pid = waitpid(-1, &status, wait_flags); 3985
3986 /* It's wrong to call waitpid() outside of INT_OFF region:
3987 * signal can arrive just after syscall return and handler can
3988 * longjmp away, losing stop/exit notification processing.
3989 * Thus, for "jobs" builtin, and for waiting for a fg job,
3990 * we call waitpid() (blocking or non-blocking) inside INT_OFF.
3991 *
3992 * However, for "wait" builtin it is wrong to simply call waitpid()
3993 * in INT_OFF region: "wait" needs to wait for any running job
3994 * to change state, but should exit on any trap too.
3995 * In INT_OFF region, a signal just before syscall entry can set
3996 * pending_sig valiables, but we can't check them, and we would
3997 * either enter a sleeping waitpid() (BUG), or need to busy-loop.
3998 * Because of this, we run inside INT_OFF, but use a special routine
3999 * which combines waitpid() and sigsuspend().
4000 */
4001 INT_OFF;
4002 if (block == DOWAIT_BLOCK_OR_SIG)
4003 pid = wait_block_or_sig(&status, wait_flags);
4004 else
4005 /* NB: _not_ safe_waitpid, we need to detect EINTR. */
4006 pid = waitpid(-1, &status, wait_flags);
3951 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n", 4007 TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
3952 pid, status, errno, strerror(errno))); 4008 pid, status, errno, strerror(errno)));
3953 if (pid <= 0) 4009 if (pid <= 0)
3954 return pid; 4010 goto out;
3955 4011
3956 INT_OFF;
3957 thisjob = NULL; 4012 thisjob = NULL;
3958 for (jp = curjob; jp; jp = jp->prev_job) { 4013 for (jp = curjob; jp; jp = jp->prev_job) {
3959 int jobstate; 4014 int jobstate;
@@ -4217,7 +4272,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4217 * with an exit status greater than 128, immediately after which 4272 * with an exit status greater than 128, immediately after which
4218 * the trap is executed." 4273 * the trap is executed."
4219 */ 4274 */
4220 dowait(DOWAIT_BLOCK, NULL); ///DOWAIT_WAITCMD 4275 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4221 /* if child sends us a signal *and immediately exits*, 4276 /* if child sends us a signal *and immediately exits*,
4222 * dowait() returns pid > 0. Check this case, 4277 * dowait() returns pid > 0. Check this case,
4223 * not "if (dowait() < 0)"! 4278 * not "if (dowait() < 0)"!
@@ -4244,7 +4299,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
4244 } 4299 }
4245 /* loop until process terminated or stopped */ 4300 /* loop until process terminated or stopped */
4246 while (job->state == JOBRUNNING) { 4301 while (job->state == JOBRUNNING) {
4247 dowait(DOWAIT_BLOCK, NULL); ///DOWAIT_WAITCMD 4302 dowait(DOWAIT_BLOCK_OR_SIG, NULL);
4248 if (pending_sig) 4303 if (pending_sig)
4249 goto sigout; 4304 goto sigout;
4250 } 4305 }
@@ -13113,7 +13168,9 @@ init(void)
13113 /* we will never free this */ 13168 /* we will never free this */
13114 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ); 13169 basepf.next_to_pgetc = basepf.buf = ckmalloc(IBUFSIZ);
13115 13170
13116 signal(SIGCHLD, SIG_DFL); 13171 sigmode[SIGCHLD - 1] = S_DFL;
13172 setsignal(SIGCHLD);
13173
13117 /* bash re-enables SIGHUP which is SIG_IGNed on entry. 13174 /* bash re-enables SIGHUP which is SIG_IGNed on entry.
13118 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" 13175 * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$"
13119 */ 13176 */