From a9ad660bd39cc2cf07ce4ada2af08fb1ded4f7ac Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 2 May 2008 22:48:58 +0000 Subject: users/12812: fix hang with confusion over process numbers --- Src/jobs.c | 9 +++++++ Src/signals.c | 76 +++++++++++++++++++++++++++++++++++++---------------------- Src/zsh.h | 36 ++++++++++++++-------------- 3 files changed, 75 insertions(+), 46 deletions(-) (limited to 'Src') diff --git a/Src/jobs.c b/Src/jobs.c index 1b3d37c63..a8767ac39 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -153,6 +153,15 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux) for (i = 1; i <= maxjob; i++) { + /* + * We are only interested in jobs with processes still + * marked as live. Careful in case there's an identical + * process number in a job we haven't quite got around + * to deleting. + */ + if (jobtab[i].stat & STAT_DONE) + continue; + for (pn = aux ? jobtab[i].auxprocs : jobtab[i].procs; pn; pn = pn->next) if (pn->pid == pid) { diff --git a/Src/signals.c b/Src/signals.c index ba01e2bc9..317df59b8 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -408,15 +408,21 @@ zhandler(int sig) signal_process(sig); sigfillset(&newmask); - oldmask = signal_block(newmask); /* Block all signals temporarily */ + /* Block all signals temporarily */ + oldmask = signal_block(newmask); #if defined(NO_SIGNAL_BLOCKING) - do_jump = suspend_longjmp; /* do we need to longjmp to signal_suspend */ - suspend_longjmp = 0; /* In case a SIGCHLD somehow arrives */ - - if (sig == SIGCHLD) { /* Traps can cause nested signal_suspend() */ - if (do_jump) - jump_to = suspend_jmp_buf; /* Copy suspend_jmp_buf */ + /* do we need to longjmp to signal_suspend */ + do_jump = suspend_longjmp; + /* In case a SIGCHLD somehow arrives */ + suspend_longjmp = 0; + + /* Traps can cause nested signal_suspend() */ + if (sig == SIGCHLD) { + if (do_jump) { + /* Copy suspend_jmp_buf */ + jump_to = suspend_jmp_buf; + } } #endif @@ -425,30 +431,36 @@ zhandler(int sig) int temp_rear = ++queue_rear % MAX_QUEUE_SIZE; DPUTS(temp_rear == queue_front, "BUG: signal queue full"); - if (temp_rear != queue_front) { /* Make sure it's not full (extremely unlikely) */ - queue_rear = temp_rear; /* ok, not full, so add to queue */ - signal_queue[queue_rear] = sig; /* save signal caught */ - signal_mask_queue[queue_rear] = oldmask; /* save current signal mask */ + /* Make sure it's not full (extremely unlikely) */ + if (temp_rear != queue_front) { + /* ok, not full, so add to queue */ + queue_rear = temp_rear; + /* save signal caught */ + signal_queue[queue_rear] = sig; + /* save current signal mask */ + signal_mask_queue[queue_rear] = oldmask; } signal_reset(sig); return; } - signal_setmask(oldmask); /* Reset signal mask, signal traps ok now */ + /* Reset signal mask, signal traps ok now */ + signal_setmask(oldmask); switch (sig) { case SIGCHLD: /* keep WAITING until no more child processes to reap */ - for (;;) - cont: { - int old_errno = errno; /* save the errno, since WAIT may change it */ + for (;;) { + /* save the errno, since WAIT may change it */ + int old_errno = errno; int status; Job jn; Process pn; - pid_t pid; + pid_t pid; pid_t *procsubpid = &cmdoutpid; int *procsubval = &cmdoutval; + int cont = 0; struct execstack *es = exstack; /* @@ -471,8 +483,8 @@ zhandler(int sig) # endif #endif - if (!pid) /* no more children to reap */ - break; + if (!pid) /* no more children to reap */ + break; /* check if child returned was from process substitution */ for (;;) { @@ -483,7 +495,8 @@ zhandler(int sig) else *procsubval = WEXITSTATUS(status); get_usage(); - goto cont; + cont = 1; + break; } if (!es) break; @@ -491,16 +504,22 @@ zhandler(int sig) procsubval = &es->cmdoutval; es = es->next; } + if (cont) + continue; /* check for WAIT error */ - if (pid == -1) { - if (errno != ECHILD) - zerr("wait failed: %e", errno); - errno = old_errno; /* WAIT changed errno, so restore the original */ - break; - } + if (pid == -1) { + if (errno != ECHILD) + zerr("wait failed: %e", errno); + /* WAIT changed errno, so restore the original */ + errno = old_errno; + break; + } - /* Find the process and job containing this pid and update it. */ + /* + * Find the process and job containing this pid and + * update it. + */ if (findproc(pid, &jn, &pn, 0)) { #if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE) struct timezone dummy_tz; @@ -517,11 +536,12 @@ zhandler(int sig) } else { /* If not found, update the shell record of time spent by * children in sub processes anyway: otherwise, this - * will get added on to the next found process that terminates. + * will get added on to the next found process that + * terminates. */ get_usage(); } - } + } break; case SIGHUP: diff --git a/Src/zsh.h b/Src/zsh.h index 54a31507f..d83bdd2bb 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -857,24 +857,24 @@ struct job { struct ttyinfo *ty; /* the modes specified by STTY */ }; -#define STAT_CHANGED (1<<0) /* status changed and not reported */ -#define STAT_STOPPED (1<<1) /* all procs stopped or exited */ -#define STAT_TIMED (1<<2) /* job is being timed */ -#define STAT_DONE (1<<3) /* job is done */ -#define STAT_LOCKED (1<<4) /* shell is finished creating this job, */ - /* may be deleted from job table */ -#define STAT_NOPRINT (1<<5) /* job was killed internally, */ - /* we don't want to show that */ -#define STAT_INUSE (1<<6) /* this job entry is in use */ -#define STAT_SUPERJOB (1<<7) /* job has a subjob */ -#define STAT_SUBJOB (1<<8) /* job is a subjob */ -#define STAT_WASSUPER (1<<9) /* was a super-job, sub-job needs to be */ - /* deleted */ -#define STAT_CURSH (1<<10) /* last command is in current shell */ -#define STAT_NOSTTY (1<<11) /* the tty settings are not inherited */ - /* from this job when it exits. */ -#define STAT_ATTACH (1<<12) /* delay reattaching shell to tty */ -#define STAT_SUBLEADER (1<<13) /* is super-job, but leader is sub-shell */ +#define STAT_CHANGED (0x0001) /* status changed and not reported */ +#define STAT_STOPPED (0x0002) /* all procs stopped or exited */ +#define STAT_TIMED (0x0004) /* job is being timed */ +#define STAT_DONE (0x0008) /* job is done */ +#define STAT_LOCKED (0x0010) /* shell is finished creating this job, */ + /* may be deleted from job table */ +#define STAT_NOPRINT (0x0020) /* job was killed internally, */ + /* we don't want to show that */ +#define STAT_INUSE (0x0040) /* this job entry is in use */ +#define STAT_SUPERJOB (0x0080) /* job has a subjob */ +#define STAT_SUBJOB (0x0100) /* job is a subjob */ +#define STAT_WASSUPER (0x0200) /* was a super-job, sub-job needs to be */ + /* deleted */ +#define STAT_CURSH (0x0400) /* last command is in current shell */ +#define STAT_NOSTTY (0x0800) /* the tty settings are not inherited */ + /* from this job when it exits. */ +#define STAT_ATTACH (0x1000) /* delay reattaching shell to tty */ +#define STAT_SUBLEADER (0x2000) /* is super-job, but leader is sub-shell */ #define SP_RUNNING -1 /* fake status for jobs currently running */ -- cgit 1.4.1