diff options
author | Barton E. Schaefer <schaefer@zsh.org> | 2015-08-09 00:50:36 -0700 |
---|---|---|
committer | Barton E. Schaefer <schaefer@zsh.org> | 2015-08-09 16:13:52 -0700 |
commit | 9958684574bf8b0ecec6983cca57f3fa3dd7cd63 (patch) | |
tree | 81d83526e0bccdb20b3bee421131b7e0b889f361 /Src/exec.c | |
parent | ce12868837f0140b95ac748f9c35047b4ea4277a (diff) | |
download | zsh-9958684574bf8b0ecec6983cca57f3fa3dd7cd63.tar.gz zsh-9958684574bf8b0ecec6983cca57f3fa3dd7cd63.tar.xz zsh-9958684574bf8b0ecec6983cca57f3fa3dd7cd63.zip |
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.
Diffstat (limited to 'Src/exec.c')
-rw-r--r-- | Src/exec.c | 49 |
1 files changed, 42 insertions, 7 deletions
diff --git a/Src/exec.c b/Src/exec.c index 7612d4303..a635c18ed 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -1121,10 +1121,14 @@ execsimple(Estate state) fflush(xtrerr); } lv = (errflag ? errflag : cmdoutval); - } else if (code == WC_FUNCDEF) { - lv = execfuncdef(state, NULL); } else { - lv = (execfuncs[code - WC_CURSH])(state, 0); + int q = queue_signal_level(); + dont_queue_signals(); + if (code == WC_FUNCDEF) + lv = execfuncdef(state, NULL); + else + lv = (execfuncs[code - WC_CURSH])(state, 0); + restore_queue_signals(q); } thisjob = otj; @@ -1158,6 +1162,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; @@ -1428,6 +1434,8 @@ sublist_done: /* Make sure this doesn't get executed again. */ sigtrapped[SIGEXIT] = 0; } + + unqueue_signals(); } /* Execute a pipeline. * @@ -1456,6 +1464,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(); @@ -1468,6 +1484,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) @@ -1523,6 +1540,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 { @@ -1580,15 +1598,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 && @@ -1672,6 +1693,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))) { @@ -3391,6 +3413,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 @@ -3431,11 +3454,14 @@ execcmd(Estate state, int input, int output, int how, int last1) } else redir_prog = NULL; + dont_queue_signals(); lastval = execfuncdef(state, redir_prog); + restore_queue_signals(q); } else if (type >= WC_CURSH) { if (last1 == 1) do_exec = 1; + dont_queue_signals(); if (type == WC_AUTOFN) { /* * We pre-loaded this to get any redirs. @@ -3444,6 +3470,7 @@ execcmd(Estate state, int input, int output, int how, int last1) lastval = execautofn_basic(state, do_exec); } else 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 */ @@ -3610,7 +3637,9 @@ execcmd(Estate state, int input, int output, int how, int last1) } state->pc = opc; } + dont_queue_signals(); lastval = execbuiltin(args, assigns, (Builtin) hn); + restore_queue_signals(q); fflush(stdout); if (save[1] == -2) { if (ferror(stdout)) { @@ -4820,11 +4849,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; @@ -5039,6 +5066,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; @@ -5261,6 +5290,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) } popheap(); + unqueue_signals(); + /* * Exit with a tidy up. * Only leave if we're at the end of the appropriate function --- @@ -5299,6 +5330,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); @@ -5320,12 +5353,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 * |