From 178e62dbfe464b56e3f12b01a159781d39b7bd85 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 12 Jan 2017 20:56:20 +0000 Subject: 40342: Add directory name cache for autoload file paths. This renders "autoload /blah/blah/*" as efficient as use of fpath. --- Src/signals.c | 1 + 1 file changed, 1 insertion(+) (limited to 'Src/signals.c') diff --git a/Src/signals.c b/Src/signals.c index 9e05add09..2de57434a 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -811,6 +811,7 @@ dosavetrap(int sig, int level) newshf->node.nam = ztrdup(shf->node.nam); newshf->node.flags = shf->node.flags; newshf->funcdef = dupeprog(shf->funcdef, 0); + /* Assume this is a real filename, don't use dircache */ newshf->filename = ztrdup(shf->filename); if (shf->sticky) { newshf->sticky = sticky_emulation_dup(shf->sticky, 0); -- cgit v1.2.3 From f90a0447aada3ad2fa114210c62b855a3e60cb1d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 16 Jan 2017 10:31:56 +0000 Subject: 40353 with tweaks to whence -v: extend directory cache use. Now used for all autoloaded functions after load, including those where the file was found along fpath, reducing duplication of directory names. --- ChangeLog | 7 +++++ Src/exec.c | 82 +++++++++++++++++++++++++++++++++++++++------------------ Src/hashtable.c | 27 ++++++++++++++++--- Src/signals.c | 7 +++-- 4 files changed, 92 insertions(+), 31 deletions(-) (limited to 'Src/signals.c') diff --git a/ChangeLog b/ChangeLog index 02a4469c3..a407dda03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-01-16 Peter Stephenson + + * 40353 (plus improvement to whence -v): Src/exec.c, + Src/hashtable.c, Src/signals.c: use directory cache where + possible for all functions loaded from directory including + fpath. + 2017-01-15 Peter Stephenson * 40362: Src/Zle/computil.c: need duplicated values for setting diff --git a/Src/exec.c b/Src/exec.c index 7a5d2bdf3..6c8264394 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -5124,12 +5124,12 @@ execautofn_basic(Estate state, UNUSED(int do_exec)) * defined yet. */ if (funcstack && !funcstack->filename) - funcstack->filename = dupstring(shf->filename); + funcstack->filename = getshfuncfile(shf); oldscriptname = scriptname; oldscriptfilename = scriptfilename; scriptname = dupstring(shf->node.nam); - scriptfilename = dupstring(shf->filename); + scriptfilename = getshfuncfile(shf); execode(shf->funcdef, 1, 0, "loadautofunc"); scriptname = oldscriptname; scriptfilename = oldscriptfilename; @@ -5150,13 +5150,47 @@ execautofn(Estate state, UNUSED(int do_exec)) return execautofn_basic(state, 0); } +/* + * Helper function to install the source file name of a shell function + * just autoloaded. + * + * We attempt to do this efficiently as the typical case is the + * directory part is a well-known directory, which is cached, and + * the non-directory part is the same as the node name. + */ + +/**/ +static void +loadautofnsetfile(Shfunc shf, char *fdir) +{ + /* + * If shf->filename is already the load directory --- + * keep it as we can still use it to get the load file. + * This makes autoload with an absolute path particularly efficient. + */ + if (!(shf->node.flags & PM_LOADDIR) || + strcmp(shf->filename, fdir) != 0) { + /* Old directory name not useful... */ + dircache_set(&shf->filename, NULL); + if (fdir) { + /* ...can still cache directory */ + shf->node.flags |= PM_LOADDIR; + dircache_set(&shf->filename, fdir); + } else { + /* ...no separate directory part to cache, for some reason. */ + shf->node.flags &= ~PM_LOADDIR; + shf->filename = ztrdup(shf->node.nam); + } + } +} + /**/ Shfunc loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) { int noalias = noaliases, ksh = 1; Eprog prog; - char *fname; + char *fdir; /* Directory path where func found */ pushheap(); @@ -5167,13 +5201,13 @@ loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) char *spec_path[2]; spec_path[0] = dupstring(shf->filename); spec_path[1] = NULL; - prog = getfpfunc(shf->node.nam, &ksh, &fname, spec_path, 0); + prog = getfpfunc(shf->node.nam, &ksh, &fdir, spec_path, 0); if (prog == &dummy_eprog && (current_fpath || (shf->node.flags & PM_CUR_FPATH))) - prog = getfpfunc(shf->node.nam, &ksh, &fname, NULL, 0); + prog = getfpfunc(shf->node.nam, &ksh, &fdir, NULL, 0); } else - prog = getfpfunc(shf->node.nam, &ksh, &fname, NULL, 0); + prog = getfpfunc(shf->node.nam, &ksh, &fdir, NULL, 0); noaliases = noalias; if (ksh == 1) { @@ -5192,7 +5226,6 @@ loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) return NULL; } if (!prog) { - zsfree(fname); popheap(); return NULL; } @@ -5205,10 +5238,8 @@ loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) shf->funcdef = prog; else shf->funcdef = dupeprog(prog, 0); - shf->node.flags &= ~(PM_UNDEFINED|PM_LOADDIR); - dircache_set(&shf->filename, NULL); - /* Full filename, don't use dircache */ - shf->filename = fname; + shf->node.flags &= ~PM_UNDEFINED; + loadautofnsetfile(shf, fdir); } else { VARARR(char, n, strlen(shf->node.nam) + 1); strcpy(n, shf->node.nam); @@ -5220,7 +5251,6 @@ loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) zwarn("%s: function not defined by file", n); locallevel++; popheap(); - zsfree(fname); return NULL; } } @@ -5230,10 +5260,8 @@ loadautofn(Shfunc shf, int fksh, int autol, int current_fpath) shf->funcdef = stripkshdef(prog, shf->node.nam); else shf->funcdef = dupeprog(stripkshdef(prog, shf->node.nam), 0); - shf->node.flags &= ~(PM_UNDEFINED|PM_LOADDIR); - dircache_set(&shf->filename, NULL); - /* Full filename, don't use dircache */ - shf->filename = fname; + shf->node.flags &= ~PM_UNDEFINED; + loadautofnsetfile(shf, fdir); } popheap(); @@ -5453,7 +5481,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) funcstack = &fstack; fstack.flineno = shfunc->lineno; - fstack.filename = dupstring(shfunc->filename); + fstack.filename = getshfuncfile(shfunc); prog = shfunc->funcdef; if (prog->flags & EF_RUN) { @@ -5623,16 +5651,17 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name) * Search fpath for an undefined function. Finds the file, and returns the * list of its contents. * - * If test is 0, load the function; *fname is set to zalloc'ed location. + * If test is 0, load the function. * * If test_only is 1, don't load function, just test for it: - * - Non-null return means function was found - * - *fname points to path at which found (not duplicated) + * Non-null return means function was found + * + * *fdir points to path at which found (as passed in, not duplicated) */ /**/ Eprog -getfpfunc(char *s, int *ksh, char **fname, char **alt_path, int test_only) +getfpfunc(char *s, int *ksh, char **fdir, char **alt_path, int test_only) { char **pp, buf[PATH_MAX+1]; off_t len; @@ -5650,8 +5679,8 @@ getfpfunc(char *s, int *ksh, char **fname, char **alt_path, int test_only) else strcpy(buf, s); if ((r = try_dump_file(*pp, s, buf, ksh, test_only))) { - if (fname) - *fname = test_only ? *pp : ztrdup(buf); + if (fdir) + *fdir = *pp; return r; } unmetafy(buf, NULL); @@ -5661,7 +5690,8 @@ getfpfunc(char *s, int *ksh, char **fname, char **alt_path, int test_only) (len = lseek(fd, 0, 2)) != -1) { if (test_only) { close(fd); - *fname = *pp; + if (fdir) + *fdir = *pp; return &dummy_eprog; } d = (char *) zalloc(len + 1); @@ -5677,8 +5707,8 @@ getfpfunc(char *s, int *ksh, char **fname, char **alt_path, int test_only) r = parse_string(d, 1); scriptname = oldscriptname; - if (fname) - *fname = ztrdup(buf); + if (fdir) + *fdir = *pp; zfree(d, len + 1); diff --git a/Src/hashtable.c b/Src/hashtable.c index a3a38f705..1f2789d07 100644 --- a/Src/hashtable.c +++ b/Src/hashtable.c @@ -926,10 +926,13 @@ printshfuncnode(HashNode hn, int printflags) (f->node.flags & PM_UNDEFINED) ? " is an autoload shell function" : " is a shell function"); - if (f->filename && (printflags & PRINT_WHENCE_VERBOSE) && - strcmp(f->filename, f->node.nam) != 0) { + if ((printflags & PRINT_WHENCE_VERBOSE) && f->filename) { printf(" from "); quotedzputs(f->filename, stdout); + if (f->node.flags & PM_LOADDIR) { + printf("/"); + quotedzputs(f->node.nam, stdout); + } } putchar('\n'); return; @@ -959,7 +962,7 @@ printshfuncnode(HashNode hn, int printflags) zputs("builtin autoload -X", stdout); for (fl=0;fopt[fl];fl++) if (f->node.flags & flgs[fl]) putchar(fopt[fl]); - if (f->filename) { + if (f->filename && (f->node.flags & PM_LOADDIR)) { putchar(' '); zputs(f->filename, stdout); } @@ -1041,6 +1044,24 @@ printshfuncexpand(HashNode hn, int printflags, int expand) text_expand_tabs = save_expand; } +/* + * Get a heap-duplicated name of the shell function, for + * use in tracing. + */ + +/**/ +mod_export char * +getshfuncfile(Shfunc shf) +{ + if (shf->node.flags & PM_LOADDIR) { + return zhtricat(shf->filename, "/", shf->node.nam); + } else if (shf->filename) { + return dupstring(shf->filename); + } else { + return NULL; + } +} + /**************************************/ /* Reserved Word Hash Table Functions */ /**************************************/ diff --git a/Src/signals.c b/Src/signals.c index 2de57434a..a7176771a 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -811,8 +811,11 @@ dosavetrap(int sig, int level) newshf->node.nam = ztrdup(shf->node.nam); newshf->node.flags = shf->node.flags; newshf->funcdef = dupeprog(shf->funcdef, 0); - /* Assume this is a real filename, don't use dircache */ - newshf->filename = ztrdup(shf->filename); + if (shf->node.flags & PM_LOADDIR) { + dircache_set(&newshf->filename, shf->filename); + } else { + newshf->filename = ztrdup(shf->filename); + } if (shf->sticky) { newshf->sticky = sticky_emulation_dup(shf->sticky, 0); } else -- cgit v1.2.3 From 12d950ba0cc345d047c94c9d94325dbfe47fc79d Mon Sep 17 00:00:00 2001 From: "Barton E. Schaefer" Date: Thu, 23 Feb 2017 16:19:07 -0800 Subject: 40624: conditionally handle WIFCONTINUED to properly set SP_RUNNING process status --- ChangeLog | 5 +++++ Src/signals.c | 5 +++++ 2 files changed, 10 insertions(+) (limited to 'Src/signals.c') diff --git a/ChangeLog b/ChangeLog index d3ce452bc..8a0e059a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-02-23 Barton E. Schaefer + + * 40624 (cf. Danek Duvall, 40563): Src/signals.c: conditionally + handle WIFCONTINUED to properly set SP_RUNNING process status + 2017-02-23 Jun-ichi Takimoto * 40604: configure.ac, Src/watch.c: revert to the old method if diff --git a/Src/signals.c b/Src/signals.c index a7176771a..68a7ae34d 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -522,6 +522,11 @@ wait_for_processes(void) #if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE) struct timezone dummy_tz; gettimeofday(&pn->endtime, &dummy_tz); +#ifdef WIFCONTINUED + if (WIFCONTINUED(status)) + pn->status = SP_RUNNING; + else +#endif pn->status = status; pn->ti = ru; #else -- cgit v1.2.3 From d7110d8f01cae8c8d51c7abd0255f533cd8b8623 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 27 Apr 2017 18:56:18 +0100 Subject: 41012: Fix premature exit from nested function in EXIT trap. Also add check so we don't delay an exit if we were already in an EXIT trap for the main shell, as we should in that case leave immediately. --- ChangeLog | 8 ++++++++ Src/builtin.c | 23 ++++++++++++++++------- Src/exec.c | 5 ++++- Src/signals.c | 11 +++++++++++ Test/C03traps.ztst | 21 +++++++++++++++++++++ 5 files changed, 60 insertions(+), 8 deletions(-) (limited to 'Src/signals.c') diff --git a/ChangeLog b/ChangeLog index fb0d379e2..243957455 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-04-27 Peter Stephenson + + * 41012: Src/builtin.c, Src/exec.c, Src/signals.c, + Test/C03traps.ztst: Fix early exit from nested functions in EXIT + trap. Drive-by fix of testing for need to exit if exiting when + already in EXIT trap for main shell --- we should just leave + immediately. + 2017-04-27 Peter Stephenson * 41016: Test/A01grammar.ztst: test that quoted precommand diff --git a/Src/builtin.c b/Src/builtin.c index b2e552db7..063644efb 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -5500,7 +5500,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) } /*FALLTHROUGH*/ case BIN_EXIT: - if (locallevel > forklevel) { + if (locallevel > forklevel && shell_exiting != -1) { /* * We don't exit directly from functions to allow tidying * up, in particular EXIT traps. We still need to perform @@ -5509,6 +5509,9 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func) * * If we are forked, we exit the shell at the function depth * at which we became a subshell, hence the comparison. + * + * If we are already exiting... give this all up as + * a bad job. */ if (stopmsg || (zexit(0,2), !stopmsg)) { retflag = 1; @@ -5555,6 +5558,14 @@ checkjobs(void) } } +/* + * -1 if the shell is already committed to exit. + * positive if zexit() was already called. + */ + +/**/ +int shell_exiting; + /* exit the shell. val is the return value of the shell. * * from_where is * 1 if zexit is called because of a signal @@ -5566,10 +5577,8 @@ checkjobs(void) mod_export void zexit(int val, int from_where) { - static int in_exit; - /* Don't do anything recursively: see below */ - if (in_exit == -1) + if (shell_exiting == -1) return; if (isset(MONITOR) && !stopmsg && from_where != 1) { @@ -5582,14 +5591,14 @@ zexit(int val, int from_where) } } /* Positive in_exit means we have been here before */ - if (from_where == 2 || (in_exit++ && from_where)) + if (from_where == 2 || (shell_exiting++ && from_where)) return; /* - * We're now committed to exiting. Set in_exit to -1 to + * We're now committed to exiting. Set shell_exiting to -1 to * indicate we shouldn't do any recursive processing. */ - in_exit = -1; + shell_exiting = -1; /* * We want to do all remaining processing regardless of preceding * errors, even user interrupts. diff --git a/Src/exec.c b/Src/exec.c index 978a32d20..e0fc54445 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -5688,8 +5688,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) * the only likely case where we need that second test is * when we have an "always" block. The endparamscope() has * already happened, hence the "+1" here. + * + * If we are in an exit trap, finish it first... we wouldn't set + * exit_pending if we were already in one. */ - if (exit_pending && exit_level >= locallevel+1) { + if (exit_pending && exit_level >= locallevel+1 && !in_exit_trap) { if (locallevel > forklevel) { /* Still functions to return: force them to do so. */ retflag = 1; diff --git a/Src/signals.c b/Src/signals.c index 68a7ae34d..cad40f4eb 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -55,6 +55,11 @@ mod_export Eprog siglists[VSIGCOUNT]; /**/ mod_export int nsigtrapped; +/* Running an exit trap? */ + +/**/ +int in_exit_trap; + /* * Flag that exit trap has been set in POSIX mode. * The setter's expectation is therefore that it is run @@ -1435,7 +1440,13 @@ dotrap(int sig) dont_queue_signals(); + if (sig == SIGEXIT) + ++in_exit_trap; + dotrapargs(sig, sigtrapped+sig, funcprog); + if (sig == SIGEXIT) + --in_exit_trap; + restore_queue_signals(q); } diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst index 7bc0b486d..759401225 100644 --- a/Test/C03traps.ztst +++ b/Test/C03traps.ztst @@ -756,6 +756,27 @@ F:Must be tested with a top-level script rather than source or function >'' >hello + $ZTST_testdir/../Src/zsh -f =(<<<" + trap handler EXIT + handler() { + echoa + echo b + } + echoa() { + echo a + } + exit0() { + exit + } + main() { + exit0 + } + main + ") +0:No early exit from nested function in EXIT trap. +>a +>b + %clean rm -f TRAPEXIT -- cgit v1.2.3