summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2008-05-02 22:48:58 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2008-05-02 22:48:58 +0000
commita9ad660bd39cc2cf07ce4ada2af08fb1ded4f7ac (patch)
tree8933013889ef16d36536793e35a5ed0952c5b0ad /Src
parenta8854f71ebb7670e49cf0481f26ede1c807ba177 (diff)
downloadzsh-a9ad660bd39cc2cf07ce4ada2af08fb1ded4f7ac.tar.gz
zsh-a9ad660bd39cc2cf07ce4ada2af08fb1ded4f7ac.zip
users/12812: fix hang with confusion over process numbers
Diffstat (limited to 'Src')
-rw-r--r--Src/jobs.c9
-rw-r--r--Src/signals.c76
-rw-r--r--Src/zsh.h36
3 files changed, 75 insertions, 46 deletions
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 */