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/loop.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/loop.c')
-rw-r--r-- | Src/loop.c | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/Src/loop.c b/Src/loop.c index e4e8e2df8..4def9b652 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); @@ -69,10 +73,12 @@ execfor(Estate state, int do_exec) fprintf(xtrerr, "%s\n", str2); fflush(xtrerr); } - if (!errflag) + if (!errflag) { matheval(str); + } if (errflag) { state->pc = end; + simple_pline = old_simple_pline; return 1; } cond = ecgetstr(state, EC_NODUP, &ctok); @@ -85,12 +91,14 @@ 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) { execsubst(args); if (errflag) { state->pc = end; + simple_pline = old_simple_pline; return 1; } } @@ -198,6 +206,7 @@ execfor(Estate state, int do_exec) popheap(); cmdpop(); loops--; + simple_pline = old_simple_pline; state->pc = end; return lastval; } @@ -214,6 +223,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); @@ -229,18 +242,21 @@ 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) { execsubst(args); if (errflag) { state->pc = end; + simple_pline = old_simple_pline; return 1; } } } if (!args || empty(args)) { state->pc = end; + simple_pline = old_simple_pline; return 0; } loops++; @@ -315,6 +331,7 @@ execselect(Estate state, UNUSED(int do_exec)) popheap(); fclose(inp); loops--; + simple_pline = old_simple_pline; state->pc = end; return lastval; } @@ -382,6 +399,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; @@ -396,8 +414,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) @@ -409,7 +425,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) @@ -421,7 +444,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) @@ -452,6 +482,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); @@ -484,6 +518,7 @@ execrepeat(Estate state, UNUSED(int do_exec)) cmdpop(); popheap(); loops--; + simple_pline = old_simple_pline; state->pc = end; return lastval; } |