mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-09-26 05:51:08 +02:00
36853: replace pushheap/popheap by NEWHEAPS/OLDHEAPS in doshfunc() to optimize memory management
Includes re-indentation that was not done in the posted patch.
This commit is contained in:
parent
bab1fc5043
commit
827d360776
2 changed files with 214 additions and 209 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2015-10-14 Barton E. Schaefer <schaefer@zsh.org>
|
||||||
|
|
||||||
|
* 36853: Src/exec.c: replace pushheap/popheap by NEWHEAPS/OLDHEAPS
|
||||||
|
in doshfunc() to optimize memory management
|
||||||
|
|
||||||
2015-10-14 Peter Stephenson <p.stephenson@samsung.com>
|
2015-10-14 Peter Stephenson <p.stephenson@samsung.com>
|
||||||
|
|
||||||
* 36856: Doc/Zsh/contrib.yo, Functions/Chpwd/cdr: add -p and -P
|
* 36856: Doc/Zsh/contrib.yo, Functions/Chpwd/cdr: add -p and -P
|
||||||
|
|
418
Src/exec.c
418
Src/exec.c
|
@ -5067,230 +5067,230 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
|
||||||
#ifdef MAX_FUNCTION_DEPTH
|
#ifdef MAX_FUNCTION_DEPTH
|
||||||
static int funcdepth;
|
static int funcdepth;
|
||||||
#endif
|
#endif
|
||||||
|
Heap funcheap;
|
||||||
|
|
||||||
queue_signals(); /* Lots of memory and global state changes coming */
|
queue_signals(); /* Lots of memory and global state changes coming */
|
||||||
|
|
||||||
pushheap();
|
NEWHEAPS(funcheap) {
|
||||||
|
oargv0 = NULL;
|
||||||
|
obreaks = breaks;
|
||||||
|
ocontflag = contflag;
|
||||||
|
oloops = loops;
|
||||||
|
if (trap_state == TRAP_STATE_PRIMED)
|
||||||
|
trap_return--;
|
||||||
|
oldlastval = lastval;
|
||||||
|
oldnumpipestats = numpipestats;
|
||||||
|
if (noreturnval) {
|
||||||
|
/*
|
||||||
|
* Easiest to use the heap here since we're bracketed
|
||||||
|
* immediately by a pushheap/popheap pair.
|
||||||
|
*/
|
||||||
|
size_t bytes = sizeof(int)*numpipestats;
|
||||||
|
oldpipestats = (int *)zhalloc(bytes);
|
||||||
|
memcpy(oldpipestats, pipestats, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
oargv0 = NULL;
|
starttrapscope();
|
||||||
obreaks = breaks;
|
startpatternscope();
|
||||||
ocontflag = contflag;
|
|
||||||
oloops = loops;
|
pptab = pparams;
|
||||||
if (trap_state == TRAP_STATE_PRIMED)
|
if (!(flags & PM_UNDEFINED))
|
||||||
trap_return--;
|
scriptname = dupstring(name);
|
||||||
oldlastval = lastval;
|
oldzoptind = zoptind;
|
||||||
oldnumpipestats = numpipestats;
|
oldoptcind = optcind;
|
||||||
if (noreturnval) {
|
if (!isset(POSIXBUILTINS)) {
|
||||||
|
zoptind = 1;
|
||||||
|
optcind = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to save the current options even if LOCALOPTIONS is *
|
||||||
|
* not currently set. That's because if it gets set in the *
|
||||||
|
* function we need to restore the original options on exit. */
|
||||||
|
memcpy(saveopts, opts, sizeof(opts));
|
||||||
|
saveemulation = emulation;
|
||||||
|
save_sticky = sticky;
|
||||||
|
|
||||||
|
if (sticky_emulation_differs(shfunc->sticky)) {
|
||||||
|
/*
|
||||||
|
* Function is marked for sticky emulation.
|
||||||
|
* Enable it now.
|
||||||
|
*
|
||||||
|
* We deliberately do not do this if the sticky emulation
|
||||||
|
* in effect is the same as that requested. This enables
|
||||||
|
* option setting naturally within emulation environments.
|
||||||
|
* Note that a difference in EMULATE_FULLY (emulate with
|
||||||
|
* or without -R) counts as a different environment.
|
||||||
|
*
|
||||||
|
* This propagates the sticky emulation to subfunctions.
|
||||||
|
*/
|
||||||
|
sticky = sticky_emulation_dup(shfunc->sticky, 1);
|
||||||
|
emulation = sticky->emulation;
|
||||||
|
restore_sticky = 1;
|
||||||
|
installemulation(emulation, opts);
|
||||||
|
if (sticky->n_on_opts) {
|
||||||
|
OptIndex *onptr;
|
||||||
|
for (onptr = sticky->on_opts;
|
||||||
|
onptr < sticky->on_opts + sticky->n_on_opts;
|
||||||
|
onptr++)
|
||||||
|
opts[*onptr] = 1;
|
||||||
|
}
|
||||||
|
if (sticky->n_off_opts) {
|
||||||
|
OptIndex *offptr;
|
||||||
|
for (offptr = sticky->off_opts;
|
||||||
|
offptr < sticky->off_opts + sticky->n_off_opts;
|
||||||
|
offptr++)
|
||||||
|
opts[*offptr] = 0;
|
||||||
|
}
|
||||||
|
/* All emulations start with pattern disables clear */
|
||||||
|
clearpatterndisables();
|
||||||
|
} else
|
||||||
|
restore_sticky = 0;
|
||||||
|
|
||||||
|
if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
|
||||||
|
opts[XTRACE] = 1;
|
||||||
|
else if (oflags & PM_TAGGED_LOCAL)
|
||||||
|
opts[XTRACE] = 0;
|
||||||
|
ooflags = oflags;
|
||||||
/*
|
/*
|
||||||
* Easiest to use the heap here since we're bracketed
|
* oflags is static, because we compare it on the next recursive
|
||||||
* immediately by a pushheap/popheap pair.
|
* call. Hence also we maintain ooflags for restoring the previous
|
||||||
|
* value of oflags after the call.
|
||||||
*/
|
*/
|
||||||
size_t bytes = sizeof(int)*numpipestats;
|
oflags = flags;
|
||||||
oldpipestats = (int *)zhalloc(bytes);
|
opts[PRINTEXITVALUE] = 0;
|
||||||
memcpy(oldpipestats, pipestats, bytes);
|
if (doshargs) {
|
||||||
}
|
LinkNode node;
|
||||||
|
|
||||||
starttrapscope();
|
node = firstnode(doshargs);
|
||||||
startpatternscope();
|
pparams = x = (char **) zshcalloc(((sizeof *x) *
|
||||||
|
(1 + countlinknodes(doshargs))));
|
||||||
pptab = pparams;
|
if (isset(FUNCTIONARGZERO)) {
|
||||||
if (!(flags & PM_UNDEFINED))
|
oargv0 = argzero;
|
||||||
scriptname = dupstring(name);
|
argzero = ztrdup(getdata(node));
|
||||||
oldzoptind = zoptind;
|
}
|
||||||
oldoptcind = optcind;
|
/* first node contains name regardless of option */
|
||||||
if (!isset(POSIXBUILTINS)) {
|
node = node->next;
|
||||||
zoptind = 1;
|
for (; node; node = node->next, x++)
|
||||||
optcind = 0;
|
*x = ztrdup(getdata(node));
|
||||||
}
|
} else {
|
||||||
|
pparams = (char **) zshcalloc(sizeof *pparams);
|
||||||
/* We need to save the current options even if LOCALOPTIONS is *
|
if (isset(FUNCTIONARGZERO)) {
|
||||||
* not currently set. That's because if it gets set in the *
|
oargv0 = argzero;
|
||||||
* function we need to restore the original options on exit. */
|
argzero = ztrdup(argzero);
|
||||||
memcpy(saveopts, opts, sizeof(opts));
|
}
|
||||||
saveemulation = emulation;
|
|
||||||
save_sticky = sticky;
|
|
||||||
|
|
||||||
if (sticky_emulation_differs(shfunc->sticky)) {
|
|
||||||
/*
|
|
||||||
* Function is marked for sticky emulation.
|
|
||||||
* Enable it now.
|
|
||||||
*
|
|
||||||
* We deliberately do not do this if the sticky emulation
|
|
||||||
* in effect is the same as that requested. This enables
|
|
||||||
* option setting naturally within emulation environments.
|
|
||||||
* Note that a difference in EMULATE_FULLY (emulate with
|
|
||||||
* or without -R) counts as a different environment.
|
|
||||||
*
|
|
||||||
* This propagates the sticky emulation to subfunctions.
|
|
||||||
*/
|
|
||||||
sticky = sticky_emulation_dup(shfunc->sticky, 1);
|
|
||||||
emulation = sticky->emulation;
|
|
||||||
restore_sticky = 1;
|
|
||||||
installemulation(emulation, opts);
|
|
||||||
if (sticky->n_on_opts) {
|
|
||||||
OptIndex *onptr;
|
|
||||||
for (onptr = sticky->on_opts;
|
|
||||||
onptr < sticky->on_opts + sticky->n_on_opts;
|
|
||||||
onptr++)
|
|
||||||
opts[*onptr] = 1;
|
|
||||||
}
|
}
|
||||||
if (sticky->n_off_opts) {
|
|
||||||
OptIndex *offptr;
|
|
||||||
for (offptr = sticky->off_opts;
|
|
||||||
offptr < sticky->off_opts + sticky->n_off_opts;
|
|
||||||
offptr++)
|
|
||||||
opts[*offptr] = 0;
|
|
||||||
}
|
|
||||||
/* All emulations start with pattern disables clear */
|
|
||||||
clearpatterndisables();
|
|
||||||
} else
|
|
||||||
restore_sticky = 0;
|
|
||||||
|
|
||||||
if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
|
|
||||||
opts[XTRACE] = 1;
|
|
||||||
else if (oflags & PM_TAGGED_LOCAL)
|
|
||||||
opts[XTRACE] = 0;
|
|
||||||
ooflags = oflags;
|
|
||||||
/*
|
|
||||||
* oflags is static, because we compare it on the next recursive
|
|
||||||
* call. Hence also we maintain ooflags for restoring the previous
|
|
||||||
* value of oflags after the call.
|
|
||||||
*/
|
|
||||||
oflags = flags;
|
|
||||||
opts[PRINTEXITVALUE] = 0;
|
|
||||||
if (doshargs) {
|
|
||||||
LinkNode node;
|
|
||||||
|
|
||||||
node = firstnode(doshargs);
|
|
||||||
pparams = x = (char **) zshcalloc(((sizeof *x) *
|
|
||||||
(1 + countlinknodes(doshargs))));
|
|
||||||
if (isset(FUNCTIONARGZERO)) {
|
|
||||||
oargv0 = argzero;
|
|
||||||
argzero = ztrdup(getdata(node));
|
|
||||||
}
|
|
||||||
/* first node contains name regardless of option */
|
|
||||||
node = node->next;
|
|
||||||
for (; node; node = node->next, x++)
|
|
||||||
*x = ztrdup(getdata(node));
|
|
||||||
} else {
|
|
||||||
pparams = (char **) zshcalloc(sizeof *pparams);
|
|
||||||
if (isset(FUNCTIONARGZERO)) {
|
|
||||||
oargv0 = argzero;
|
|
||||||
argzero = ztrdup(argzero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef MAX_FUNCTION_DEPTH
|
#ifdef MAX_FUNCTION_DEPTH
|
||||||
if(++funcdepth > MAX_FUNCTION_DEPTH)
|
if(++funcdepth > MAX_FUNCTION_DEPTH)
|
||||||
{
|
{
|
||||||
zerr("maximum nested function level reached");
|
zerr("maximum nested function level reached");
|
||||||
goto undoshfunc;
|
goto undoshfunc;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fstack.name = dupstring(name);
|
fstack.name = dupstring(name);
|
||||||
/*
|
|
||||||
* The caller is whatever is immediately before on the stack,
|
|
||||||
* unless we're at the top, in which case it's the script
|
|
||||||
* or interactive shell name.
|
|
||||||
*/
|
|
||||||
fstack.caller = funcstack ? funcstack->name :
|
|
||||||
dupstring(oargv0 ? oargv0 : argzero);
|
|
||||||
fstack.lineno = lineno;
|
|
||||||
fstack.prev = funcstack;
|
|
||||||
fstack.tp = FS_FUNC;
|
|
||||||
funcstack = &fstack;
|
|
||||||
|
|
||||||
fstack.flineno = shfunc->lineno;
|
|
||||||
fstack.filename = dupstring(shfunc->filename);
|
|
||||||
|
|
||||||
prog = shfunc->funcdef;
|
|
||||||
if (prog->flags & EF_RUN) {
|
|
||||||
Shfunc shf;
|
|
||||||
|
|
||||||
prog->flags &= ~EF_RUN;
|
|
||||||
|
|
||||||
runshfunc(prog, NULL, fstack.name);
|
|
||||||
|
|
||||||
if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
|
|
||||||
(name = fname)))) {
|
|
||||||
zwarn("%s: function not defined by file", name);
|
|
||||||
if (noreturnval)
|
|
||||||
errflag |= ERRFLAG_ERROR;
|
|
||||||
else
|
|
||||||
lastval = 1;
|
|
||||||
goto doneshfunc;
|
|
||||||
}
|
|
||||||
prog = shf->funcdef;
|
|
||||||
}
|
|
||||||
runshfunc(prog, wrappers, fstack.name);
|
|
||||||
doneshfunc:
|
|
||||||
funcstack = fstack.prev;
|
|
||||||
#ifdef MAX_FUNCTION_DEPTH
|
|
||||||
undoshfunc:
|
|
||||||
--funcdepth;
|
|
||||||
#endif
|
|
||||||
if (retflag) {
|
|
||||||
retflag = 0;
|
|
||||||
breaks = obreaks;
|
|
||||||
}
|
|
||||||
freearray(pparams);
|
|
||||||
if (oargv0) {
|
|
||||||
zsfree(argzero);
|
|
||||||
argzero = oargv0;
|
|
||||||
}
|
|
||||||
pparams = pptab;
|
|
||||||
if (!isset(POSIXBUILTINS)) {
|
|
||||||
zoptind = oldzoptind;
|
|
||||||
optcind = oldoptcind;
|
|
||||||
}
|
|
||||||
scriptname = oldscriptname;
|
|
||||||
oflags = ooflags;
|
|
||||||
|
|
||||||
endpatternscope(); /* before restoring old LOCALPATTERNS */
|
|
||||||
|
|
||||||
if (restore_sticky) {
|
|
||||||
/*
|
/*
|
||||||
* If we switched to an emulation environment just for
|
* The caller is whatever is immediately before on the stack,
|
||||||
* this function, we interpret the option and emulation
|
* unless we're at the top, in which case it's the script
|
||||||
* switch as being a firewall between environments.
|
* or interactive shell name.
|
||||||
*/
|
*/
|
||||||
memcpy(opts, saveopts, sizeof(opts));
|
fstack.caller = funcstack ? funcstack->name :
|
||||||
emulation = saveemulation;
|
dupstring(oargv0 ? oargv0 : argzero);
|
||||||
sticky = save_sticky;
|
fstack.lineno = lineno;
|
||||||
} else if (isset(LOCALOPTIONS)) {
|
fstack.prev = funcstack;
|
||||||
/* restore all shell options except PRIVILEGED and RESTRICTED */
|
fstack.tp = FS_FUNC;
|
||||||
saveopts[PRIVILEGED] = opts[PRIVILEGED];
|
funcstack = &fstack;
|
||||||
saveopts[RESTRICTED] = opts[RESTRICTED];
|
|
||||||
memcpy(opts, saveopts, sizeof(opts));
|
|
||||||
emulation = saveemulation;
|
|
||||||
} else {
|
|
||||||
/* just restore a couple. */
|
|
||||||
opts[XTRACE] = saveopts[XTRACE];
|
|
||||||
opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
|
|
||||||
opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
|
|
||||||
opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts[LOCALLOOPS]) {
|
fstack.flineno = shfunc->lineno;
|
||||||
if (contflag)
|
fstack.filename = dupstring(shfunc->filename);
|
||||||
zwarn("`continue' active at end of function scope");
|
|
||||||
if (breaks)
|
|
||||||
zwarn("`break' active at end of function scope");
|
|
||||||
breaks = obreaks;
|
|
||||||
contflag = ocontflag;
|
|
||||||
loops = oloops;
|
|
||||||
}
|
|
||||||
|
|
||||||
endtrapscope();
|
prog = shfunc->funcdef;
|
||||||
|
if (prog->flags & EF_RUN) {
|
||||||
|
Shfunc shf;
|
||||||
|
|
||||||
if (trap_state == TRAP_STATE_PRIMED)
|
prog->flags &= ~EF_RUN;
|
||||||
trap_return++;
|
|
||||||
ret = lastval;
|
runshfunc(prog, NULL, fstack.name);
|
||||||
if (noreturnval) {
|
|
||||||
lastval = oldlastval;
|
if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
|
||||||
numpipestats = oldnumpipestats;
|
(name = fname)))) {
|
||||||
memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
|
zwarn("%s: function not defined by file", name);
|
||||||
}
|
if (noreturnval)
|
||||||
popheap();
|
errflag |= ERRFLAG_ERROR;
|
||||||
|
else
|
||||||
|
lastval = 1;
|
||||||
|
goto doneshfunc;
|
||||||
|
}
|
||||||
|
prog = shf->funcdef;
|
||||||
|
}
|
||||||
|
runshfunc(prog, wrappers, fstack.name);
|
||||||
|
doneshfunc:
|
||||||
|
funcstack = fstack.prev;
|
||||||
|
#ifdef MAX_FUNCTION_DEPTH
|
||||||
|
undoshfunc:
|
||||||
|
--funcdepth;
|
||||||
|
#endif
|
||||||
|
if (retflag) {
|
||||||
|
retflag = 0;
|
||||||
|
breaks = obreaks;
|
||||||
|
}
|
||||||
|
freearray(pparams);
|
||||||
|
if (oargv0) {
|
||||||
|
zsfree(argzero);
|
||||||
|
argzero = oargv0;
|
||||||
|
}
|
||||||
|
pparams = pptab;
|
||||||
|
if (!isset(POSIXBUILTINS)) {
|
||||||
|
zoptind = oldzoptind;
|
||||||
|
optcind = oldoptcind;
|
||||||
|
}
|
||||||
|
scriptname = oldscriptname;
|
||||||
|
oflags = ooflags;
|
||||||
|
|
||||||
|
endpatternscope(); /* before restoring old LOCALPATTERNS */
|
||||||
|
|
||||||
|
if (restore_sticky) {
|
||||||
|
/*
|
||||||
|
* If we switched to an emulation environment just for
|
||||||
|
* this function, we interpret the option and emulation
|
||||||
|
* switch as being a firewall between environments.
|
||||||
|
*/
|
||||||
|
memcpy(opts, saveopts, sizeof(opts));
|
||||||
|
emulation = saveemulation;
|
||||||
|
sticky = save_sticky;
|
||||||
|
} else if (isset(LOCALOPTIONS)) {
|
||||||
|
/* restore all shell options except PRIVILEGED and RESTRICTED */
|
||||||
|
saveopts[PRIVILEGED] = opts[PRIVILEGED];
|
||||||
|
saveopts[RESTRICTED] = opts[RESTRICTED];
|
||||||
|
memcpy(opts, saveopts, sizeof(opts));
|
||||||
|
emulation = saveemulation;
|
||||||
|
} else {
|
||||||
|
/* just restore a couple. */
|
||||||
|
opts[XTRACE] = saveopts[XTRACE];
|
||||||
|
opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
|
||||||
|
opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
|
||||||
|
opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts[LOCALLOOPS]) {
|
||||||
|
if (contflag)
|
||||||
|
zwarn("`continue' active at end of function scope");
|
||||||
|
if (breaks)
|
||||||
|
zwarn("`break' active at end of function scope");
|
||||||
|
breaks = obreaks;
|
||||||
|
contflag = ocontflag;
|
||||||
|
loops = oloops;
|
||||||
|
}
|
||||||
|
|
||||||
|
endtrapscope();
|
||||||
|
|
||||||
|
if (trap_state == TRAP_STATE_PRIMED)
|
||||||
|
trap_return++;
|
||||||
|
ret = lastval;
|
||||||
|
if (noreturnval) {
|
||||||
|
lastval = oldlastval;
|
||||||
|
numpipestats = oldnumpipestats;
|
||||||
|
memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
|
||||||
|
}
|
||||||
|
} OLDHEAPS;
|
||||||
|
|
||||||
unqueue_signals();
|
unqueue_signals();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue