mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
The forking fix implemented in102868f8and9d428f8f, which stops the main shell's hash table from being cleared if PATH is changed in a subshell, can cause a significant performance penalty for certain scripts that do something like ( PATH=... command foo ) in a subshell, especially if done repeatedly. This is because the hash table is cleared (and hence a subshell forks) even for temporary PATH assignments preceding commands. It also just plain doesn't work. For instance: $ hash -r; (ls) >/dev/null; hash ls=/bin/ls Simply running an external command in a subshell caches the path in the hash table that is shared with a main shell. To remedy this, we would have to fork the subshell before forking any external command. And that would be an unacceptable performance regression. Virtual subshells do not need to fork when changing PATH if they get their own hash tables. This commit adds these. The code for alias subshell trees (which was removed inec888867because they were broken and unneeded) provided the beginning of a template for their implementation. src/cmd/ksh93/sh/subshell.c: - struct subshell: Add strack pointer to subshell hash table. - Add sh_subtracktree(): return pointer to subshell hash table. - sh_subfuntree(): Refactor a bit for legibility. - sh_subshell(): Add code for cleaning up subshell hash table. src/cmd/ksh93/sh/name.c: - nv_putval(): Remove code to fork a subshell upon resetting PATH. - nv_rehash(): When in a subshell, invalidate a hash table entry for a subshell by creating the subshell scope if needed, then giving that entry the NV_NOALIAS attribute to invalidate it. src/cmd/ksh93/sh/path.c: path_search(): - To set a tracked alias/hash table entry, use sh_subtracktree() and pass the HASH_NOSCOPE flag to nv_search() so that any new entries are added to the current subshell table (if any) and do not influence any parent scopes. src/cmd/ksh93/bltins/typeset.c: b_alias(): - b_alias(): For hash table entries, use sh_subtracktree() instead of forking a subshell. Keep forking for normal aliases. - setall(): To set a tracked alias/hash table entry, pass the HASH_NOSCOPE flag to nv_search() so that any new entries are added to the current subshell table (if any) and do not influence any parent scopes. src/cmd/ksh93/sh/init.c: put_restricted(): - Update code for clearing the hash table (when changing $PATH) to use sh_subtracktree(). src/cmd/ksh93/bltins/cd_pwd.c: - When invalidating path name bindings to relative paths, use the subshell hash tree if applicable by calling sh_subtracktree(). - rehash(): Call nv_rehash() instead of _nv_unset()ting the hash table entry; this is needed to work correctly in subshells. src/cmd/ksh93/tests/leaks.sh: - Add leak tests for various PATH-related operations in the main shell and in a virtual subshell. - Several pre-existing memory leaks are exposed by the new tests (I've confirmed these in 93u+). The tests are disabled and marked TODO for now, as these bugs have not yet been fixed. src/cmd/ksh93/tests/subshell.sh: - Update. Resolves: https://github.com/ksh93/ksh/issues/66
This commit is contained in:
parent
a95d107ee5
commit
222515bf08
11 changed files with 177 additions and 67 deletions
|
|
@ -1570,17 +1570,6 @@ void nv_putval(register Namval_t *np, const char *string, int flags)
|
|||
#endif /* SHOPT_FIXEDARRAY */
|
||||
if(!(flags&NV_RDONLY) && nv_isattr (np, NV_RDONLY))
|
||||
errormsg(SH_DICT,ERROR_exit(1),e_readonly, nv_name(np));
|
||||
|
||||
/*
|
||||
* Resetting the PATH in a non-forking subshell will reset the parent shell's
|
||||
* hash table, so work around the problem by forking before sh_assignok
|
||||
* -- however, don't do this if we were told to ignore the variable's readonly state (i.e.
|
||||
* if the NV_RDONLY flag is set), because that means we're restoring the parent shell state
|
||||
* after exiting a virtual subshell, and we would end up forking the parent shell instead.
|
||||
*/
|
||||
if(np == PATHNOD && !(flags & NV_RDONLY) && shp->subshell && !shp->subshare)
|
||||
sh_subfork();
|
||||
|
||||
/*
|
||||
* The following could cause the shell to fork if assignment
|
||||
* would cause a side effect
|
||||
|
|
@ -2244,6 +2233,11 @@ static int scanfilter(Dt_t *dict, void *arg, void *data)
|
|||
void nv_rehash(register Namval_t *np,void *data)
|
||||
{
|
||||
NOT_USED(data);
|
||||
if(sh.subshell)
|
||||
{
|
||||
/* invalidate subshell node; if none exists, add a dummy */
|
||||
np = nv_search(nv_name(np),sh.track_tree,NV_ADD|HASH_NOSCOPE);
|
||||
}
|
||||
nv_onattr(np,NV_NOALIAS);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue