about summary refs log tree commit diff
path: root/Src/jobs.c
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2022-11-06 11:25:47 -0800
committerBart Schaefer <schaefer@zsh.org>2022-11-06 11:25:47 -0800
commit188c5cd518b512073d3fd1dbf09c91b7968efcaa (patch)
tree687a4b83ae3de16f1a9fbfb48b7b8b19a3ff1852 /Src/jobs.c
parentf8d93888a8efd6c8142e74ece83b38632661de47 (diff)
downloadzsh-188c5cd518b512073d3fd1dbf09c91b7968efcaa.tar.gz
zsh-188c5cd518b512073d3fd1dbf09c91b7968efcaa.tar.xz
zsh-188c5cd518b512073d3fd1dbf09c91b7968efcaa.zip
50874: fix handling of tty signals for jobs in the current shell when waiting for the right side of a pipeline.
Reverts 15bf8ace (workers/50134).  Thanks to Jun T. for debugging assistance.

Issues came down to two things:
1. update_job() may be called on a process group leader even when a
   signal was NOT sent to any process in that process group.  This
   caused jobs to be resumed or backgrounded incorrectly or in the
   wrong order.
2. When there is a current-shell complex command (in braces) on the
   right side of a pipeline, external processes within it have their
   own process groups, but a tty signal sent to such a process should
   be treated as if received by the whole complex command.

This fixes:
* Suspend/resume of a foreground pipeline within a shell function
* Interrupt or suspend/resume of processes in a pipeline ending in { ... }
* Interrupt of such a pipeline after exit of the last process in { ... }

These affected interactive shells only (MONITOR set plus tty signals).
Diffstat (limited to 'Src/jobs.c')
-rw-r--r--Src/jobs.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/Src/jobs.c b/Src/jobs.c
index 707374297..76c762ee5 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -544,16 +544,14 @@ update_job(Job jn)
 
     if (isset(MONITOR)) {
 	pid_t pgrp = gettygrp();           /* get process group of tty      */
+	int deadpgrp = (mypgrp != pgrp && inforeground && pgrp > 1 &&
+			kill(-pgrp, 0) == -1 && errno == ESRCH);
 
 	/* is this job in the foreground of an interactive shell? */
 	if (mypgrp != pgrp && inforeground &&
-	    (jn->gleader == pgrp ||
-	     (pgrp > 1 &&
-	      (kill(-pgrp, 0) == -1 && errno == ESRCH)))) {
+	    ((jn->gleader == pgrp && signalled) || deadpgrp)) {
 	    if (list_pipe) {
-		if (somestopped || (pgrp > 1 &&
-				    kill(-pgrp, 0) == -1 &&
-				    errno == ESRCH)) {
+		if (somestopped || deadpgrp) {
 		    attachtty(mypgrp);
 		    /* check window size and adjust if necessary */
 		    adjustwinsize(0);
@@ -566,6 +564,12 @@ update_job(Job jn)
 		     * when the job is finally deleted.
 		     */
 		    jn->stat |= STAT_ATTACH;
+		    /*
+		     * If we're in shell jobs on the right side of a pipeline
+		     * we should treat it like a job in the current shell.
+		     */
+		    if (inforeground == 2)
+			inforeground = 1;
 		}
 		/* If we have `foo|while true; (( x++ )); done', and hit
 		 * ^C, we have to stop the loop, too. */
@@ -1488,10 +1492,7 @@ addproc(pid_t pid, char *text, int aux, struct timeval *bgtime,
 	 * set it for that, too.
 	 */
 	if (gleader != -1) {
-	    if (jobtab[thisjob].stat & STAT_CURSH)
-		jobtab[thisjob].gleader = gleader;
-	    else
-		jobtab[thisjob].gleader = pid;
+	    jobtab[thisjob].gleader = gleader;
 	    if (list_pipe_job_used != -1)
 		jobtab[list_pipe_job_used].gleader = gleader;
 	    /*
@@ -1500,7 +1501,7 @@ addproc(pid_t pid, char *text, int aux, struct timeval *bgtime,
 	     */
 	    last_attached_pgrp = gleader;
 	} else if (!jobtab[thisjob].gleader)
-		jobtab[thisjob].gleader = pid;
+	    jobtab[thisjob].gleader = pid;
 	/* attach this process to end of process list of current job */
 	pnlist = &jobtab[thisjob].procs;
     }
@@ -2506,6 +2507,7 @@ bin_fg(char *name, char **argv, Options ops, int func)
 		jobtab[job].stat &= ~STAT_CURSH;
 	    }
 	    if ((stopped = (jobtab[job].stat & STAT_STOPPED))) {
+		/* WIFCONTINUED will makerunning() again at killjb() */
 		makerunning(jobtab + job);
 		if (func == BIN_BG) {
 		    /* Set $! to indicate this was backgrounded */