summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--Doc/Zsh/expn.yo5
-rw-r--r--Src/exec.c2
-rw-r--r--Src/jobs.c59
-rw-r--r--Src/signals.c229
5 files changed, 201 insertions, 110 deletions
diff --git a/ChangeLog b/ChangeLog
index 46fa559db..9291ee3d1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2010-08-22 Peter Stephenson <p.w.stephenson@ntlworld.com>
+
+ * 28179: Src/jobs.c, Src/signals.c: use WIFCONTINUED() and
+ WCONTINUE by exporting child handler to a function.
+
+ * users/15314: Doc/Zsh/expn.yo: redescribe process substitution.
+
+ * users/15310 (bits applying to process substitution with
+ redirection): Src/exec.c: make redirection process substitution
+ attach to the appropriate process group.
+
+ * users/15200: pass foreground signals on to process
+ substitutions in current shell
+
2010-08-22 Barton E. Schaefer <schaefer@zsh.org>
* 28186: Completion/Base/Utility/_multi_parts: replace a single
@@ -13550,5 +13564,5 @@
*****************************************************
* This is used by the shell to define $ZSH_PATCHLEVEL
-* $Revision: 1.5061 $
+* $Revision: 1.5062 $
*****************************************************
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index ecb16c0d5..cacbfc4d3 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -390,7 +390,8 @@ Process substitutions may be used following redirection operators; in this
case, the substitution must appear with no trailing string.
In the case of the tt(<) or tt(>) forms, the shell runs the commands in
-var(list) asynchronously. If the system supports the tt(/dev/fd)
+var(list) as a subprocess of the job executing the shell command line.
+If the system supports the tt(/dev/fd)
mechanism, the command argument is the name of the device file
corresponding to a file descriptor; otherwise, if the system supports named
pipes (FIFOs), the command argument will be a named pipe. If the form with
@@ -456,7 +457,7 @@ version of the example above:
example(tt(paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR()) tt(> >LPAR())var(process)tt(RPAR()))
(note that no tt(MULTIOS) are involved), var(process) will be run
-asynchronously. The workaround is:
+asynchronously as far as the parent shell is concerned. The workaround is:
example(tt({ paste <LPAR()cut -f1) var(file1)tt(RPAR() <LPAR()cut -f3) var(file2)tt(RPAR() }) tt(> >LPAR())var(process)tt(RPAR()))
diff --git a/Src/exec.c b/Src/exec.c
index 73b4c01a8..3ab4aa90b 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3905,7 +3905,7 @@ getpipe(char *cmd, int nullexec)
addproc(pid, NULL, 1, &bgtime);
return pipes[!out];
}
- entersubsh(ESUB_ASYNC|ESUB_PGRP);
+ entersubsh(ESUB_PGRP);
redup(pipes[out], out);
closem(FDT_UNUSED); /* this closes pipes[!out] as well */
cmdpush(CS_CMDSUBST);
diff --git a/Src/jobs.c b/Src/jobs.c
index a40291a88..fd785a0e9 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -320,6 +320,36 @@ update_process(Process pn, int status)
}
#endif
+/*
+ * Called when the current shell is behaving as if it received
+ * a interactively generated signal (sig).
+ *
+ * As we got the signal or are pretending we did, we need to pretend
+ * anything attached to a CURSH process got it, too.
+ */
+/**/
+void
+check_cursh_sig(int sig)
+{
+ int i, j;
+
+ if (!errflag)
+ return;
+ for (i = 1; i <= maxjob; i++) {
+ if ((jobtab[i].stat & (STAT_CURSH|STAT_DONE)) ==
+ STAT_CURSH) {
+ for (j = 0; j < 2; j++) {
+ Process pn = j ? jobtab[i].auxprocs : jobtab[i].procs;
+ for (; pn; pn = pn->next) {
+ if (pn->status == SP_RUNNING) {
+ kill(pn->pid, sig);
+ }
+ }
+ }
+ }
+ }
+}
+
/* Update status of job, possibly printing it */
/**/
@@ -331,11 +361,20 @@ update_job(Job jn)
int val = 0, status = 0;
int somestopped = 0, inforeground = 0;
- for (pn = jn->auxprocs; pn; pn = pn->next)
+ for (pn = jn->auxprocs; pn; pn = pn->next) {
+#ifdef WIFCONTINUED
+ if (WIFCONTINUED(pn->status))
+ pn->status = SP_RUNNING;
+#endif
if (pn->status == SP_RUNNING)
return;
+ }
for (pn = jn->procs; pn; pn = pn->next) {
+#ifdef WIFCONTINUED
+ if (WIFCONTINUED(pn->status))
+ pn->status = SP_RUNNING;
+#endif
if (pn->status == SP_RUNNING) /* some processes in this job are running */
return; /* so no need to update job table entry */
if (WIFSTOPPED(pn->status)) /* some processes are stopped */
@@ -496,6 +535,7 @@ update_job(Job jn)
breaks = loops;
errflag = 1;
}
+ check_cursh_sig(sig);
}
}
}
@@ -1793,6 +1833,14 @@ bin_fg(char *name, char **argv, Options ops, int func)
}
queue_signals();
+ /*
+ * In case any processes changed state recently, wait for them.
+ * This updates stopped processes (but we should have been
+ * signalled about those, up to inevitable races), and also
+ * continued processes if that feature is available.
+ */
+ wait_for_processes();
+
/* If necessary, update job table. */
if (unset(NOTIFY))
scanjobs();
@@ -2216,8 +2264,11 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
job, and send the job a SIGCONT if sending it a non-stopping
signal. */
if (jobtab[p].stat & STAT_STOPPED) {
+#ifndef WIFCONTINUED
+ /* With WIFCONTINUED we find this out properly */
if (sig == SIGCONT)
makerunning(jobtab + p);
+#endif
if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP
&& sig != SIGTTOU && sig != SIGTTIN && sig != SIGSTOP)
killjb(jobtab + p, SIGCONT);
@@ -2230,14 +2281,18 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
if (kill(pid, sig) == -1) {
zwarnnam("kill", "kill %s failed: %e", *argv, errno);
returnval++;
- } else if (sig == SIGCONT) {
+ }
+#ifndef WIFCONTINUED
+ else if (sig == SIGCONT) {
Job jn;
Process pn;
+ /* With WIFCONTINUED we find this out properly */
if (findproc(pid, &jn, &pn, 0)) {
if (WIFSTOPPED(pn->status))
pn->status = SP_RUNNING;
}
}
+#endif
}
}
unqueue_signals();
diff --git a/Src/signals.c b/Src/signals.c
index 74aeadde7..49e5e6379 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -400,6 +400,129 @@ signal_suspend(UNUSED(int sig), int wait_cmd)
/**/
int last_signal;
+/*
+ * Wait for any processes that have changed state.
+ *
+ * The main use for this is in the SIGCHLD handler. However,
+ * we also use it to pick up status changes of jobs when
+ * updating jobs.
+ */
+/**/
+void
+wait_for_processes(void)
+{
+ /* keep WAITING until no more child processes to reap */
+ for (;;) {
+ /* save the errno, since WAIT may change it */
+ int old_errno = errno;
+ int status;
+ Job jn;
+ Process pn;
+ pid_t pid;
+ pid_t *procsubpid = &cmdoutpid;
+ int *procsubval = &cmdoutval;
+ int cont = 0;
+ struct execstack *es = exstack;
+
+ /*
+ * Reap the child process.
+ * If we want usage information, we need to use wait3.
+ */
+#if defined(HAVE_WAIT3) || defined(HAVE_WAITPID)
+# ifdef WCONTINUED
+# define WAITFLAGS (WNOHANG|WUNTRACED|WCONTINUED)
+# else
+# define WAITFLAGS (WNOHANG|WUNTRACED)
+# endif
+#endif
+#ifdef HAVE_WAIT3
+# ifdef HAVE_GETRUSAGE
+ struct rusage ru;
+
+ pid = wait3((void *)&status, WAITFLAGS, &ru);
+# else
+ pid = wait3((void *)&status, WAITFLAGS, NULL);
+# endif
+#else
+# ifdef HAVE_WAITPID
+ pid = waitpid(-1, &status, WAITFLAGS);
+# else
+ pid = wait(&status);
+# endif
+#endif
+
+ if (!pid) /* no more children to reap */
+ break;
+
+ /* check if child returned was from process substitution */
+ for (;;) {
+ if (pid == *procsubpid) {
+ *procsubpid = 0;
+ if (WIFSIGNALED(status))
+ *procsubval = (0200 | WTERMSIG(status));
+ else
+ *procsubval = WEXITSTATUS(status);
+ use_cmdoutval = 1;
+ get_usage();
+ cont = 1;
+ break;
+ }
+ if (!es)
+ break;
+ procsubpid = &es->cmdoutpid;
+ procsubval = &es->cmdoutval;
+ es = es->next;
+ }
+ if (cont)
+ continue;
+
+ /* check for WAIT error */
+ 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.
+ */
+ pn = NULL;
+ if (findproc(pid, &jn, &pn, 0)) {
+#if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE)
+ struct timezone dummy_tz;
+ gettimeofday(&pn->endtime, &dummy_tz);
+ pn->status = status;
+ pn->ti = ru;
+#else
+ update_process(pn, status);
+#endif
+ update_job(jn);
+ } else if (findproc(pid, &jn, &pn, 1)) {
+ pn->status = status;
+ update_job(jn);
+ } 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.
+ */
+ get_usage();
+ }
+ /*
+ * Remember the status associated with $!, so we can
+ * wait for it even if it's exited. This value is
+ * only used if we can't find the PID in the job table,
+ * so it doesn't matter that the value we save here isn't
+ * useful until the process has exited.
+ */
+ if (pn != NULL && pid == lastpid && lastpid_status != -1L)
+ lastpid_status = lastval2;
+ }
+}
+
/* the signal handler */
/**/
@@ -458,110 +581,7 @@ zhandler(int sig)
switch (sig) {
case SIGCHLD:
-
- /* keep WAITING until no more child processes to reap */
- for (;;) {
- /* save the errno, since WAIT may change it */
- int old_errno = errno;
- int status;
- Job jn;
- Process pn;
- pid_t pid;
- pid_t *procsubpid = &cmdoutpid;
- int *procsubval = &cmdoutval;
- int cont = 0;
- struct execstack *es = exstack;
-
- /*
- * Reap the child process.
- * If we want usage information, we need to use wait3.
- */
-#ifdef HAVE_WAIT3
-# ifdef HAVE_GETRUSAGE
- struct rusage ru;
-
- pid = wait3((void *)&status, WNOHANG|WUNTRACED, &ru);
-# else
- pid = wait3((void *)&status, WNOHANG|WUNTRACED, NULL);
-# endif
-#else
-# ifdef HAVE_WAITPID
- pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
-# else
- pid = wait(&status);
-# endif
-#endif
-
- if (!pid) /* no more children to reap */
- break;
-
- /* check if child returned was from process substitution */
- for (;;) {
- if (pid == *procsubpid) {
- *procsubpid = 0;
- if (WIFSIGNALED(status))
- *procsubval = (0200 | WTERMSIG(status));
- else
- *procsubval = WEXITSTATUS(status);
- use_cmdoutval = 1;
- get_usage();
- cont = 1;
- break;
- }
- if (!es)
- break;
- procsubpid = &es->cmdoutpid;
- procsubval = &es->cmdoutval;
- es = es->next;
- }
- if (cont)
- continue;
-
- /* check for WAIT error */
- 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.
- */
- pn = NULL;
- if (findproc(pid, &jn, &pn, 0)) {
-#if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE)
- struct timezone dummy_tz;
- gettimeofday(&pn->endtime, &dummy_tz);
- pn->status = status;
- pn->ti = ru;
-#else
- update_process(pn, status);
-#endif
- update_job(jn);
- } else if (findproc(pid, &jn, &pn, 1)) {
- pn->status = status;
- update_job(jn);
- } 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.
- */
- get_usage();
- }
- /*
- * Remember the status associated with $!, so we can
- * wait for it even if it's exited. This value is
- * only used if we can't find the PID in the job table,
- * so it doesn't matter that the value we save here isn't
- * useful until the process has exited.
- */
- if (pn != NULL && pid == lastpid && lastpid_status != -1L)
- lastpid_status = lastval2;
- }
+ wait_for_processes();
break;
case SIGHUP:
@@ -580,6 +600,7 @@ zhandler(int sig)
breaks = loops;
errflag = 1;
inerrflush();
+ check_cursh_sig(SIGINT);
}
}
break;