Blob Blame History Raw
From bbeb06a37ba58f6905803d32a26fb00953459301 Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Thu, 20 Mar 2014 07:56:30 -0700
Subject: [PATCH 1/8] 32500: handle interrupts during pattern matching

Upstream-commit: 8672d19f0c0f25569e233bbd466b6c39f60c7a55
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/pattern.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Src/pattern.c b/Src/pattern.c
index b74a08a..b93b064 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -2128,6 +2128,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
 
 	return ret;
     } else {
+	int q = queue_signal_level();
+
 	/*
 	 * Test for a `must match' string, unless we're scanning for a match
 	 * in which case we don't need to do this each time.
@@ -2175,6 +2177,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
 
 	patinput = patinstart;
 
+	dont_queue_signals();
+
 	if (patmatch((Upat)progstr)) {
 	    /*
 	     * we were lazy and didn't save the globflags if an exclusion
@@ -2311,6 +2315,8 @@ pattryrefs(Patprog prog, char *string, int stringlen, int unmetalen,
 	} else
 	    ret = 0;
 
+	restore_queue_signals(q);
+
 	if (tryalloced)
 	    zfree(tryalloced, unmetalen + unmetalenp);
 
@@ -2390,7 +2396,7 @@ patmatch(Upat prog)
     zrange_t from, to, comp;
     patint_t nextch;
 
-    while  (scan) {
+    while  (scan && !errflag) {
 	next = PATNEXT(scan);
 
 	if (!globdots && P_NOTDOT(scan) && patinput == patinstart &&
-- 
2.5.0


From c3eeba82d560005d830862dace8d771e712693e6 Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Sun, 9 Aug 2015 00:50:36 -0700
Subject: [PATCH 2/8] 36022 fix bug that some loop constructs could not be
 interrupted, revise signal queueing

There are two underlying ideas here:  (1) Keeping signals queued around
anything that's doing memory management (including push/pop of the heap)
has become crucial.  (2) Anytime the shell is going to run a command, be
it buitin or external, it must be both safe and necessary to process any
queued signals, so that the apparent order of signal arrival and command
execution is preserved.

Upstream-commit: 9958684574bf8b0ecec6983cca57f3fa3dd7cd63
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/exec.c    | 43 ++++++++++++++++++++++++++++++++++++++-----
 Src/init.c    |  5 +++++
 Src/input.c   |  9 +++++++++
 Src/loop.c    | 36 ++++++++++++++++++++++++++++++++++--
 Src/parse.c   |  8 ++++++++
 Src/signals.c |  8 ++++++--
 6 files changed, 100 insertions(+), 9 deletions(-)

diff --git a/Src/exec.c b/Src/exec.c
index 7817a64..cff1a24 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1108,8 +1108,12 @@ execsimple(Estate state)
 	    fflush(xtrerr);
 	}
 	lv = (errflag ? errflag : cmdoutval);
-    } else
+    } else {
+	int q = queue_signal_level();
+	dont_queue_signals();
 	lv = (execfuncs[code - WC_CURSH])(state, 0);
+	restore_queue_signals(q);
+     }
 
     thisjob = otj;
 
@@ -1141,6 +1145,8 @@ execlist(Estate state, int dont_change_job, int exiting)
      */
     int oldnoerrexit = noerrexit;
 
+    queue_signals();
+
     cj = thisjob;
     old_pline_level = pline_level;
     old_list_pipe = list_pipe;
@@ -1391,6 +1397,8 @@ sublist_done:
 	/* Make sure this doesn't get executed again. */
 	sigtrapped[SIGEXIT] = 0;
     }
+
+    unqueue_signals();
 }
 
 /* Execute a pipeline.                                                *
@@ -1419,6 +1427,14 @@ execpline(Estate state, wordcode slcode, int how, int last1)
     else if (slflags & WC_SUBLIST_NOT)
 	last1 = 0;
 
+    /* If trap handlers are allowed to run here, they may start another
+     * external job in the middle of us starting this one, which can
+     * result in jobs being reaped before their job table entries have
+     * been initialized, which in turn leads to waiting forever for
+     * jobs that no longer exist.  So don't do that.
+     */
+    queue_signals();
+
     pj = thisjob;
     ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
     child_block();
@@ -1431,6 +1447,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
      */
     if ((thisjob = newjob = initjob()) == -1) {
 	child_unblock();
+	unqueue_signals();
 	return 1;
     }
     if (how & Z_TIMED)
@@ -1486,6 +1503,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 	else
 	    spawnjob();
 	child_unblock();
+	unqueue_signals();
 	/* Executing background code resets shell status */
 	return lastval = 0;
     } else {
@@ -1543,15 +1561,18 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		}
 		if (!(jn->stat & STAT_LOCKED)) {
 		    updated = hasprocs(thisjob);
-		    waitjobs();
+		    waitjobs();		/* deals with signal queue */
 		    child_block();
 		} else
 		    updated = 0;
 		if (!updated &&
 		    list_pipe_job && hasprocs(list_pipe_job) &&
 		    !(jobtab[list_pipe_job].stat & STAT_STOPPED)) {
+		    int q = queue_signal_level();
 		    child_unblock();
+		    dont_queue_signals();
 		    child_block();
+		    restore_queue_signals(q);
 		}
 		if (list_pipe_child &&
 		    jn->stat & STAT_DONE &&
@@ -1631,6 +1652,7 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		    break;
 	    }
 	    child_unblock();
+	    unqueue_signals();
 
 	    if (list_pipe && (lastval & 0200) && pj >= 0 &&
 		(!(jn->stat & STAT_INUSE) || (jn->stat & STAT_DONE))) {
@@ -3192,6 +3214,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 	    fflush(xtrerr);
 	}
     } else if (isset(EXECOPT) && !errflag) {
+	int q = queue_signal_level();
 	/*
 	 * We delay the entersubsh() to here when we are exec'ing
 	 * the current shell (including a fake exec to run a builtin then
@@ -3210,7 +3233,9 @@ execcmd(Estate state, int input, int output, int how, int last1)
 	if (type >= WC_CURSH) {
 	    if (last1 == 1)
 		do_exec = 1;
+	    dont_queue_signals();
 	    lastval = (execfuncs[type - WC_CURSH])(state, do_exec);
+	    restore_queue_signals(q);
 	} else if (is_builtin || is_shfunc) {
 	    LinkList restorelist = 0, removelist = 0;
 	    /* builtin or shell function */
@@ -3269,7 +3294,9 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		/* It's a builtin */
 		if (forked)
 		    closem(FDT_INTERNAL);
+		dont_queue_signals();
 		lastval = execbuiltin(args, (Builtin) hn);
+		restore_queue_signals(q);
 #ifdef PATH_DEV_FD
 		closem(FDT_PROC_SUBST);
 #endif
@@ -4415,11 +4442,9 @@ execshfunc(Shfunc shf, LinkList args)
     if ((osfc = sfcontext) == SFC_NONE)
 	sfcontext = SFC_DIRECT;
     xtrerr = stderr;
-    unqueue_signals();
 
     doshfunc(shf, args, 0);
 
-    queue_signals();
     sfcontext = osfc;
     free(cmdstack);
     cmdstack = ocs;
@@ -4614,6 +4639,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     static int funcdepth;
 #endif
 
+    queue_signals();	/* Lots of memory and global state changes coming */
+
     pushheap();
 
     oargv0 = NULL;
@@ -4814,6 +4841,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     }
     popheap();
 
+    unqueue_signals();
+
     if (exit_pending) {
 	if (locallevel > forklevel) {
 	    /* Still functions to return: force them to do so. */
@@ -4844,6 +4873,8 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
     int cont, ouu;
     char *ou;
 
+    queue_signals();
+
     ou = zalloc(ouu = underscoreused);
     if (ou)
 	memcpy(ou, zunderscore, underscoreused);
@@ -4865,12 +4896,14 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
 	wrap = wrap->next;
     }
     startparamscope();
-    execode(prog, 1, 0, "shfunc");
+    execode(prog, 1, 0, "shfunc");	/* handles signal unqueueing */
     if (ou) {
 	setunderscore(ou);
 	zfree(ou, ouu);
     }
     endparamscope();
+
+    unqueue_signals();
 }
 
 /* Search fpath for an undefined function.  Finds the file, and returns the *
diff --git a/Src/init.c b/Src/init.c
index 78f171d..df42349 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -105,6 +105,7 @@ loop(int toplevel, int justonce)
     Eprog prog;
     int err, non_empty = 0;
 
+    queue_signals();
     pushheap();
     if (!toplevel)
 	lexsave();
@@ -118,7 +119,9 @@ loop(int toplevel, int justonce)
 	    if (interact && toplevel) {
 	        int hstop = stophist;
 		stophist = 3;
+		unqueue_signals();
 		preprompt();
+		queue_signals();
 		if (stophist != 3)
 		    hbegin(1);
 		else
@@ -197,6 +200,7 @@ loop(int toplevel, int justonce)
 	if (((!interact || sourcelevel) && errflag) || retflag)
 	    break;
 	if (isset(SINGLECOMMAND) && toplevel) {
+	    dont_queue_signals();
 	    if (sigtrapped[SIGEXIT])
 		dotrap(SIGEXIT);
 	    exit(lastval);
@@ -208,6 +212,7 @@ loop(int toplevel, int justonce)
     if (!toplevel)
 	lexrestore();
     popheap();
+    unqueue_signals();
 
     if (err)
 	return LOOP_ERROR;
diff --git a/Src/input.c b/Src/input.c
index 5b782dc..dcff78a 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -140,14 +140,17 @@ shingetline(void)
     int c;
     char buf[BUFSIZ];
     char *p;
+    int q = queue_signal_level();
 
     p = buf;
     for (;;) {
+	dont_queue_signals();
 	do {
 	    errno = 0;
 	    c = fgetc(bshin);
 	} while (c < 0 && errno == EINTR);
 	if (c < 0 || c == '\n') {
+	    restore_queue_signals(q);
 	    if (c == '\n')
 		*p++ = '\n';
 	    if (p > buf) {
@@ -163,11 +166,13 @@ shingetline(void)
 	} else
 	    *p++ = c;
 	if (p >= buf + BUFSIZ - 1) {
+	    queue_signals();
 	    line = zrealloc(line, ll + (p - buf) + 1);
 	    memcpy(line + ll, buf, p - buf);
 	    ll += p - buf;
 	    line[ll] = '\0';
 	    p = buf;
+	    unqueue_signals();
 	}
     }
 }
@@ -340,6 +345,8 @@ inputline(void)
 static void
 inputsetline(char *str, int flags)
 {
+    queue_signals();
+
     if ((inbufflags & INP_FREE) && inbuf) {
 	free(inbuf);
     }
@@ -357,6 +364,8 @@ inputsetline(char *str, int flags)
     else
 	inbufct = inbufleft;
     inbufflags = flags;
+
+    unqueue_signals();
 }
 
 /*
diff --git a/Src/loop.c b/Src/loop.c
index 90a0761..0c07c73 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -56,6 +56,10 @@ execfor(Estate state, int do_exec)
     char *name, *str, *cond = NULL, *advance = NULL;
     zlong val = 0;
     LinkList vars = NULL, args = NULL;
+    int old_simple_pline = simple_pline;
+
+    /* See comments in execwhile() */
+    simple_pline = 1;
 
     end = state->pc + WC_FOR_SKIP(code);
 
@@ -73,6 +77,7 @@ execfor(Estate state, int do_exec)
 	    matheval(str);
 	if (errflag) {
 	    state->pc = end;
+	    simple_pline = old_simple_pline;
 	    return lastval = errflag;
 	}
 	cond = ecgetstr(state, EC_NODUP, &ctok);
@@ -85,6 +90,7 @@ execfor(Estate state, int do_exec)
 
 	    if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
 		state->pc = end;
+		simple_pline = old_simple_pline;
 		return 0;
 	    }
 	    if (htok)
@@ -190,6 +196,7 @@ execfor(Estate state, int do_exec)
     popheap();
     cmdpop();
     loops--;
+    simple_pline = old_simple_pline;
     state->pc = end;
     return lastval;
 }
@@ -206,6 +213,10 @@ execselect(Estate state, UNUSED(int do_exec))
     FILE *inp;
     size_t more;
     LinkList args;
+    int old_simple_pline = simple_pline;
+
+    /* See comments in execwhile() */
+    simple_pline = 1;
 
     end = state->pc + WC_FOR_SKIP(code);
     name = ecgetstr(state, EC_NODUP, NULL);
@@ -221,6 +232,7 @@ execselect(Estate state, UNUSED(int do_exec))
 
 	if (!(args = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok))) {
 	    state->pc = end;
+	    simple_pline = old_simple_pline;
 	    return 0;
 	}
 	if (htok)
@@ -228,6 +240,7 @@ execselect(Estate state, UNUSED(int do_exec))
     }
     if (!args || empty(args)) {
 	state->pc = end;
+	simple_pline = old_simple_pline;
 	return 1;
     }
     loops++;
@@ -301,6 +314,7 @@ execselect(Estate state, UNUSED(int do_exec))
     popheap();
     fclose(inp);
     loops--;
+    simple_pline = old_simple_pline;
     state->pc = end;
     return lastval;
 }
@@ -368,6 +382,7 @@ execwhile(Estate state, UNUSED(int do_exec))
     Wordcode end, loop;
     wordcode code = state->pc[-1];
     int olderrexit, oldval, isuntil = (WC_WHILE_TYPE(code) == WC_WHILE_UNTIL);
+    int old_simple_pline = simple_pline;
 
     end = state->pc + WC_WHILE_SKIP(code);
     olderrexit = noerrexit;
@@ -382,8 +397,6 @@ execwhile(Estate state, UNUSED(int do_exec))
         /* This is an empty loop.  Make sure the signal handler sets the
         * flags and then just wait for someone hitting ^C. */
 
-        int old_simple_pline = simple_pline;
-
         simple_pline = 1;
 
         while (!breaks)
@@ -395,7 +408,14 @@ execwhile(Estate state, UNUSED(int do_exec))
         for (;;) {
             state->pc = loop;
             noerrexit = 1;
+
+	    /* In case the test condition is a functional no-op,
+	     * make sure signal handlers recognize ^C to end the loop. */
+	    simple_pline = 1;
+
             execlist(state, 1, 0);
+
+	    simple_pline = old_simple_pline;
             noerrexit = olderrexit;
             if (!((lastval == 0) ^ isuntil)) {
                 if (breaks)
@@ -407,7 +427,14 @@ execwhile(Estate state, UNUSED(int do_exec))
                 lastval = oldval;
                 break;
             }
+
+	    /* In case the loop body is also a functional no-op,
+	     * make sure signal handlers recognize ^C as above. */
+	    simple_pline = 1;
+
             execlist(state, 1, 0);
+
+	    simple_pline = old_simple_pline;
             if (breaks) {
                 breaks--;
                 if (breaks || !contflag)
@@ -438,6 +465,10 @@ execrepeat(Estate state, UNUSED(int do_exec))
     wordcode code = state->pc[-1];
     int count, htok = 0;
     char *tmp;
+    int old_simple_pline = simple_pline;
+
+    /* See comments in execwhile() */
+    simple_pline = 1;
 
     end = state->pc + WC_REPEAT_SKIP(code);
 
@@ -470,6 +501,7 @@ execrepeat(Estate state, UNUSED(int do_exec))
     cmdpop();
     popheap();
     loops--;
+    simple_pline = old_simple_pline;
     state->pc = end;
     return lastval;
 }
diff --git a/Src/parse.c b/Src/parse.c
index b0a7624..04d2707 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -379,6 +379,8 @@ init_parse_status(void)
 void
 init_parse(void)
 {
+    queue_signals();
+
     if (ecbuf) zfree(ecbuf, eclen);
 
     ecbuf = (Wordcode) zalloc((eclen = EC_INIT_SIZE) * sizeof(wordcode));
@@ -389,6 +391,8 @@ init_parse(void)
     ecnfunc = 0;
 
     init_parse_status();
+
+    unqueue_signals();
 }
 
 /* Build eprog. */
@@ -409,6 +413,8 @@ bld_eprog(void)
     Eprog ret;
     int l;
 
+    queue_signals();
+
     ecadd(WCB_END());
 
     ret = (Eprog) zhalloc(sizeof(*ret));
@@ -431,6 +437,8 @@ bld_eprog(void)
     zfree(ecbuf, eclen);
     ecbuf = NULL;
 
+    unqueue_signals();
+
     return ret;
 }
 
diff --git a/Src/signals.c b/Src/signals.c
index c539063..73b41b1 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -1194,6 +1194,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
 	}
     }
 
+    queue_signals();	/* Any time we manage memory or global state */
+
     intrap++;
     *sigtr |= ZSIG_IGNORED;
 
@@ -1231,7 +1233,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
 
 	sfcontext = SFC_SIGNAL;
 	incompfunc = 0;
-	doshfunc((Shfunc)sigfn, args, 1);
+	doshfunc((Shfunc)sigfn, args, 1);	/* manages signal queueing */
 	sfcontext = osc;
 	incompfunc= old_incompfunc;
 	freelinklist(args, (FreeFunc) NULL);
@@ -1241,7 +1243,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
 	trap_state = TRAP_STATE_PRIMED;
 	trapisfunc = isfunc = 0;
 
-	execode((Eprog)sigfn, 1, 0, "trap");
+	execode((Eprog)sigfn, 1, 0, "trap");	/* manages signal queueing */
     }
     runhookdef(AFTERTRAPHOOK, NULL);
 
@@ -1286,6 +1288,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
     if (*sigtr != ZSIG_IGNORED)
 	*sigtr &= ~ZSIG_IGNORED;
     intrap--;
+
+    unqueue_signals();
 }
 
 /* Standard call to execute a trap for a given signal. */
-- 
2.5.0


From 33905958a1b94e83ca1c32bc6849906da94b91a6 Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Sun, 9 Aug 2015 17:37:23 -0700
Subject: [PATCH 3/8] 36033: a few more queue_signals() to protect global state
 changes

Upstream-commit: df5f825538720a9422859200d58d075d1dd075fc
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/glob.c    | 4 ++++
 Src/pattern.c | 8 +++++++-
 2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/Src/glob.c b/Src/glob.c
index ca2ffaf..9135fce 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -213,22 +213,26 @@ static struct globdata curglobdata;
 
 #define save_globstate(N) \
   do { \
+    queue_signals(); \
     memcpy(&(N), &curglobdata, sizeof(struct globdata)); \
     (N).gd_pathpos = pathpos; \
     (N).gd_pathbuf = pathbuf; \
     (N).gd_glob_pre = glob_pre; \
     (N).gd_glob_suf = glob_suf; \
     pathbuf = NULL; \
+    unqueue_signals(); \
   } while (0)
 
 #define restore_globstate(N) \
   do { \
+    queue_signals(); \
     zfree(pathbuf, pathbufsz); \
     memcpy(&curglobdata, &(N), sizeof(struct globdata)); \
     pathpos = (N).gd_pathpos; \
     pathbuf = (N).gd_pathbuf; \
     glob_pre = (N).gd_glob_pre; \
     glob_suf = (N).gd_glob_suf; \
+    unqueue_signals(); \
   } while (0)
 
 /* pathname component in filename patterns */
diff --git a/Src/pattern.c b/Src/pattern.c
index b74a08a..52774c0 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -452,6 +452,8 @@ patcompile(char *exp, int inflags, char **endexp)
     char *lng, *strp = NULL;
     Patprog p;
 
+    queue_signals();
+
     startoff = sizeof(struct patprog);
     /* Ensure alignment of start of program string */
     startoff = (startoff + sizeof(union upat) - 1) & ~(sizeof(union upat) - 1);
@@ -521,8 +523,10 @@ patcompile(char *exp, int inflags, char **endexp)
 	if (!strp || (*strp && *strp != '/')) {
 	    /* No, do normal compilation. */
 	    strp = NULL;
-	    if (patcompswitch(0, &flags) == 0)
+	    if (patcompswitch(0, &flags) == 0) {
+		unqueue_signals();
 		return NULL;
+	    }
 	} else {
 	    /*
 	     * Yes, copy the string, and skip compilation altogether.
@@ -654,6 +658,8 @@ patcompile(char *exp, int inflags, char **endexp)
 
     if (endexp)
 	*endexp = patparse;
+
+    unqueue_signals();
     return p;
 }
 
-- 
2.5.0


From bba38460c88c36fb529ee7494570cb2cfc68641a Mon Sep 17 00:00:00 2001
From: Peter Stephenson <pws@zsh.org>
Date: Mon, 10 Aug 2015 16:59:55 +0100
Subject: [PATCH 4/8] Don't rely on implicit value when saving background
 process status

Upstream-commit: a07f74fadd1180b42258d1fcec5359afe3f9ba00
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/signals.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Src/signals.c b/Src/signals.c
index 73b41b1..2e7304f 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -533,7 +533,14 @@ wait_for_processes(void)
 	 */
 	if (jn && !(jn->stat & (STAT_CURSH|STAT_BUILTIN)) &&
 	    jn - jobtab != thisjob)
-	    addbgstatus(pid, (int)lastval2);
+	{
+	    int val = (WIFSIGNALED(status) ?
+		   0200 | WTERMSIG(status) :
+		   (WIFSTOPPED(status) ?
+		    0200 | WEXITSTATUS(status) :
+		    WEXITSTATUS(status)));
+	    addbgstatus(pid, val);
+	}
 
 	unqueue_signals();
     }
-- 
2.5.0


From 530b59d58273c9f11cd1443c0865f6420eafcbf0 Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Tue, 11 Aug 2015 08:44:15 -0700
Subject: [PATCH 5/8] 36090: keep signals queued for preprompt()

Upstream-commit: 1af2e6e02d5cb8ca8d11f107b670cddfd10a7e81
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/init.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/Src/init.c b/Src/init.c
index df42349..ca616d3 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -119,9 +119,7 @@ loop(int toplevel, int justonce)
 	    if (interact && toplevel) {
 	        int hstop = stophist;
 		stophist = 3;
-		unqueue_signals();
 		preprompt();
-		queue_signals();
 		if (stophist != 3)
 		    hbegin(1);
 		else
-- 
2.5.0


From b2994c9f3ef36c3ee3286a08736da1e2c8d65f0b Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Tue, 11 Aug 2015 08:53:12 -0700
Subject: [PATCH 6/8] 36104: change order of child_block() and
 dont_queue_signals() to resolve yet another race condition

Upstream-commit: 128bf385b1e8256e412d732fa9b80ecd7c5e2c73
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/exec.c | 2 +-
 Src/jobs.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Src/exec.c b/Src/exec.c
index cff1a24..70e2279 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1570,8 +1570,8 @@ execpline(Estate state, wordcode slcode, int how, int last1)
 		    !(jobtab[list_pipe_job].stat & STAT_STOPPED)) {
 		    int q = queue_signal_level();
 		    child_unblock();
-		    dont_queue_signals();
 		    child_block();
+		    dont_queue_signals();
 		    restore_queue_signals(q);
 		}
 		if (list_pipe_child &&
diff --git a/Src/jobs.c b/Src/jobs.c
index 24b8494..e711a9b 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1312,9 +1312,9 @@ zwaitjob(int job, int wait_cmd)
     int q = queue_signal_level();
     Job jn = jobtab + job;
 
-    dont_queue_signals();
     child_block();		 /* unblocked during signal_suspend() */
     queue_traps(wait_cmd);
+    dont_queue_signals();
     if (jn->procs || jn->auxprocs) { /* if any forks were done         */
 	jn->stat |= STAT_LOCKED;
 	if (jn->stat & STAT_CHANGED)
@@ -1350,9 +1350,9 @@ zwaitjob(int job, int wait_cmd)
 	pipestats[0] = lastval;
 	numpipestats = 1;
     }
+    restore_queue_signals(q);
     unqueue_traps();
     child_unblock();
-    restore_queue_signals(q);
 
     return 0;
 }
-- 
2.5.0


From 6a0fd02f08972875cc138e783e28515a5c7a7e04 Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Sat, 15 Aug 2015 10:15:30 -0700
Subject: [PATCH 7/8] 36180: avoid infinite job stop/continue loop on "wait
 PID" for a background job

Upstream-commit: 5d019f426af8b2a600ee03e43782c24b357d1401
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/jobs.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/Src/jobs.c b/Src/jobs.c
index e711a9b..9b94a1f 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1276,10 +1276,17 @@ waitforpid(pid_t pid, int wait_cmd)
     dont_queue_signals();
     child_block();		/* unblocked in signal_suspend() */
     queue_traps(wait_cmd);
+
+    /* This function should never be called with a pid that is not a
+     * child of the current shell.  Consequently, if kill(0, pid)
+     * fails here with ESRCH, the child has already been reaped.  In
+     * the loop body, we expect this to happen in signal_suspend()
+     * via zhandler(), after which this test terminates the loop.
+     */
     while (!errflag && (kill(pid, 0) >= 0 || errno != ESRCH)) {
 	if (first)
 	    first = 0;
-	else
+	else if (!wait_cmd)
 	    kill(pid, SIGCONT);
 
 	last_signal = -1;
-- 
2.5.0


From d184dd8673c93d35855b4a04613ae09277214df5 Mon Sep 17 00:00:00 2001
From: "Barton E. Schaefer" <schaefer@zsh.org>
Date: Wed, 2 Sep 2015 19:11:54 -0700
Subject: [PATCH 8/8] 36393: process queued signals during dotrap()

Upstream-commit: 9f5dffa1f33ec43c306bdf3c87cebba5fcc95b64
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
---
 Src/signals.c          | 5 +++++
 Test/A05execution.ztst | 9 +++++++++
 2 files changed, 14 insertions(+)

diff --git a/Src/signals.c b/Src/signals.c
index 2e7304f..dbc84af 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -1306,6 +1306,7 @@ void
 dotrap(int sig)
 {
     void *funcprog;
+    int q = queue_signal_level();
 
     if (sigtrapped[sig] & ZSIG_FUNC) {
 	HashNode hn = gettrapnode(sig, 0);
@@ -1328,5 +1329,9 @@ dotrap(int sig)
     if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag)
 	return;
 
+    dont_queue_signals();
+
     dotrapargs(sig, sigtrapped+sig, funcprog);
+
+    restore_queue_signals(q);
 }
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
index 77c569c..3b39c75 100644
--- a/Test/A05execution.ztst
+++ b/Test/A05execution.ztst
@@ -203,3 +203,12 @@
 1:The status of recently exited background jobs is recorded
 >3
 >2
+
+# Regression test for workers/36392
+  print -u $ZTST_fd 'This test takes 3 seconds and hangs the shell when it fails...'
+  callfromchld() { true && { print CHLD } }
+  TRAPCHLD() { callfromchld }
+  sleep 2 & sleep 3; print OK
+0:Background job exit does not affect reaping foreground job
+>CHLD
+>OK
-- 
2.5.0