mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-11-01 06:20:55 +01:00
17299: Use reference counts in Eprogs so as to be able to free them as soon
as finished with.
This commit is contained in:
parent
37199039b2
commit
0e08b8c2e4
7 changed files with 76 additions and 23 deletions
|
|
@ -1,5 +1,9 @@
|
|||
2002-06-07 Peter Stephenson <pws@csr.com>
|
||||
|
||||
* 17299: Src/builtin.c, Src/exec.c, Src/init.c, Src/parse.c,
|
||||
Src/text.c, Src/zsh.h: Instead of freeing Eprogs in one go
|
||||
at the top level, use reference counts.
|
||||
|
||||
* 17301 (doc slightly tweaked): Src/Zle/zle_thingy.c,
|
||||
Doc/Zsh/zle.yo: make `zle -I' only invalidate the display on the
|
||||
first call to prevent spurious extra command lines appearing.
|
||||
|
|
|
|||
|
|
@ -2322,6 +2322,7 @@ mkautofn(Shfunc shf)
|
|||
p->strs = NULL;
|
||||
p->shf = shf;
|
||||
p->npats = 0;
|
||||
p->nref = 1; /* allocated from permanent storage */
|
||||
p->pats = (Patprog *) p->prog;
|
||||
p->flags = EF_REAL;
|
||||
p->dump = NULL;
|
||||
|
|
|
|||
|
|
@ -725,8 +725,11 @@ execode(Eprog p, int dont_change_job, int exiting)
|
|||
s.prog = p;
|
||||
s.pc = p->prog;
|
||||
s.strs = p->strs;
|
||||
useeprog(p); /* Mark as in use */
|
||||
|
||||
execlist(&s, dont_change_job, exiting);
|
||||
|
||||
freeeprog(p); /* Free if now unused */
|
||||
}
|
||||
|
||||
/* Execute a simplified command. This is used to execute things that
|
||||
|
|
@ -3134,6 +3137,7 @@ execfuncdef(Estate state, int do_exec)
|
|||
while ((s = (char *) ugetnode(names))) {
|
||||
prog = (Eprog) zalloc(sizeof(*prog));
|
||||
prog->npats = npats;
|
||||
prog->nref = 1; /* allocated from permanent storage */
|
||||
prog->len = len;
|
||||
if (state->prog->dump) {
|
||||
prog->flags = EF_MAP;
|
||||
|
|
|
|||
|
|
@ -163,8 +163,6 @@ loop(int toplevel, int justonce)
|
|||
if (stopmsg) /* unset 'you have stopped jobs' flag */
|
||||
stopmsg--;
|
||||
execode(prog, 0, 0);
|
||||
if (toplevel)
|
||||
freeeprogs();
|
||||
tok = toksav;
|
||||
if (toplevel)
|
||||
noexitct = 0;
|
||||
|
|
|
|||
65
Src/parse.c
65
Src/parse.c
|
|
@ -396,6 +396,7 @@ bld_eprog(void)
|
|||
(ecused * sizeof(wordcode)) +
|
||||
ecsoffs);
|
||||
ret->npats = ecnpats;
|
||||
ret->nref = -1; /* Eprog is on the heap */
|
||||
ret->pats = (Patprog *) zhalloc(ret->len);
|
||||
ret->prog = (Wordcode) (ret->pats + ecnpats);
|
||||
ret->strs = (char *) (ret->prog + ecused);
|
||||
|
|
@ -2085,6 +2086,12 @@ dupeprog(Eprog p, int heap)
|
|||
r->dump = NULL;
|
||||
r->len = p->len;
|
||||
r->npats = p->npats;
|
||||
/*
|
||||
* If Eprog is on the heap, reference count is not valid.
|
||||
* Otherwise, initialise reference count to 1 so that a freeeprog()
|
||||
* will delete it if it is not in use.
|
||||
*/
|
||||
r->nref = heap ? -1 : 1;
|
||||
pp = r->pats = (heap ? (Patprog *) hcalloc(r->len) :
|
||||
(Patprog *) zcalloc(r->len));
|
||||
r->prog = (Wordcode) (r->pats + r->npats);
|
||||
|
|
@ -2098,33 +2105,49 @@ dupeprog(Eprog p, int heap)
|
|||
return r;
|
||||
}
|
||||
|
||||
static LinkList eprog_free;
|
||||
|
||||
/*
|
||||
* Pair of functions to mark an Eprog as in use, and to delete it
|
||||
* when it is no longer in use, by means of the reference count in
|
||||
* then nref element.
|
||||
*
|
||||
* If nref is negative, the Eprog is on the heap and is never freed.
|
||||
*/
|
||||
|
||||
/* Increase the reference count of an Eprog so it won't be deleted. */
|
||||
|
||||
/**/
|
||||
mod_export void
|
||||
useeprog(Eprog p)
|
||||
{
|
||||
if (p && p != &dummy_eprog && p->nref >= 0)
|
||||
p->nref++;
|
||||
}
|
||||
|
||||
/* Free an Eprog if we have finished with it */
|
||||
|
||||
/**/
|
||||
mod_export void
|
||||
freeeprog(Eprog p)
|
||||
{
|
||||
if (p && p != &dummy_eprog)
|
||||
zaddlinknode(eprog_free, p);
|
||||
}
|
||||
|
||||
/**/
|
||||
void
|
||||
freeeprogs(void)
|
||||
{
|
||||
Eprog p;
|
||||
int i;
|
||||
Patprog *pp;
|
||||
|
||||
while ((p = (Eprog) getlinknode(eprog_free))) {
|
||||
for (i = p->npats, pp = p->pats; i--; pp++)
|
||||
freepatprog(*pp);
|
||||
if (p->dump) {
|
||||
decrdumpcount(p->dump);
|
||||
zfree(p->pats, p->npats * sizeof(Patprog));
|
||||
} else
|
||||
zfree(p->pats, p->len);
|
||||
zfree(p, sizeof(*p));
|
||||
if (p && p != &dummy_eprog) {
|
||||
/* paranoia */
|
||||
DPUTS(p->nref > 0 && (p->flags & EF_HEAP), "Heap EPROG has nref > 0");
|
||||
DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0");
|
||||
DPUTS(p->nref < -1 || p->nref > 256, "Uninitialised EPROG nref");
|
||||
if (p->nref > 0 && !--p->nref) {
|
||||
for (i = p->npats, pp = p->pats; i--; pp++)
|
||||
freepatprog(*pp);
|
||||
if (p->dump) {
|
||||
decrdumpcount(p->dump);
|
||||
zfree(p->pats, p->npats * sizeof(Patprog));
|
||||
} else
|
||||
zfree(p->pats, p->len);
|
||||
zfree(p, sizeof(*p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2268,8 +2291,6 @@ init_eprog(void)
|
|||
dummy_eprog.len = sizeof(wordcode);
|
||||
dummy_eprog.prog = &dummy_eprog_code;
|
||||
dummy_eprog.strs = NULL;
|
||||
|
||||
eprog_free = znewlinklist();
|
||||
}
|
||||
|
||||
/* Code for function dump files.
|
||||
|
|
@ -3057,6 +3078,7 @@ check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh)
|
|||
prog->flags = EF_MAP;
|
||||
prog->len = h->len;
|
||||
prog->npats = np = h->npats;
|
||||
prog->nref = 1; /* allocated from permanent storage */
|
||||
prog->pats = pp = (Patprog *) zalloc(np * sizeof(Patprog));
|
||||
prog->prog = f->map + h->start;
|
||||
prog->strs = ((char *) prog->prog) + h->strs;
|
||||
|
|
@ -3108,6 +3130,7 @@ check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh)
|
|||
prog->flags = EF_REAL;
|
||||
prog->len = h->len + po;
|
||||
prog->npats = np = h->npats;
|
||||
prog->nref = 1; /* allocated from permanent storage */
|
||||
prog->pats = pp = (Patprog *) d;
|
||||
prog->prog = (Wordcode) (((char *) d) + po);
|
||||
prog->strs = ((char *) prog->prog) + h->strs;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ getpermtext(Eprog prog, Wordcode c)
|
|||
if (!c)
|
||||
c = prog->prog;
|
||||
|
||||
useeprog(prog); /* mark as used */
|
||||
|
||||
s.prog = prog;
|
||||
s.pc = c;
|
||||
s.strs = prog->strs;
|
||||
|
|
@ -130,6 +132,7 @@ getpermtext(Eprog prog, Wordcode c)
|
|||
if (prog->len)
|
||||
gettext2(&s);
|
||||
*tptr = '\0';
|
||||
freeeprog(prog); /* mark as unused */
|
||||
untokenize(tbuf);
|
||||
return tbuf;
|
||||
}
|
||||
|
|
@ -147,6 +150,7 @@ getjobtext(Eprog prog, Wordcode c)
|
|||
if (!c)
|
||||
c = prog->prog;
|
||||
|
||||
useeprog(prog); /* mark as used */
|
||||
s.prog = prog;
|
||||
s.pc = c;
|
||||
s.strs = prog->strs;
|
||||
|
|
@ -159,6 +163,7 @@ getjobtext(Eprog prog, Wordcode c)
|
|||
tjob = 1;
|
||||
gettext2(&s);
|
||||
*tptr = '\0';
|
||||
freeeprog(prog); /* mark as unused */
|
||||
untokenize(jbuf);
|
||||
return jbuf;
|
||||
}
|
||||
|
|
|
|||
18
Src/zsh.h
18
Src/zsh.h
|
|
@ -497,10 +497,28 @@ struct funcdump {
|
|||
char *filename;
|
||||
};
|
||||
|
||||
/*
|
||||
* A note on the use of reference counts in Eprogs.
|
||||
*
|
||||
* When an Eprog is created, nref is set to -1 if the Eprog is on the
|
||||
* heap; then no attempt is ever made to free it. (This information is
|
||||
* already present in EF_HEAP; we use the redundancy for debugging
|
||||
* checks.)
|
||||
*
|
||||
* Otherwise, nref is initialised to 1. Calling freeprog() decrements
|
||||
* nref and frees the Eprog if the count is now zero. When the Eprog
|
||||
* is in use, we call useeprog() at the start and freeprog() at the
|
||||
* end to increment and decrement the reference counts. If an attempt
|
||||
* is made to free the Eprog from within, this will then take place
|
||||
* when execution is finished, typically in the call to freeeprog()
|
||||
* in execode(). If the Eprog was on the heap, neither useeprog()
|
||||
* nor freeeprog() has any effect.
|
||||
*/
|
||||
struct eprog {
|
||||
int flags; /* EF_* below */
|
||||
int len; /* total block length */
|
||||
int npats; /* Patprog cache size */
|
||||
int nref; /* number of references: delete when zero */
|
||||
Patprog *pats; /* the memory block, the patterns */
|
||||
Wordcode prog; /* memory block ctd, the code */
|
||||
char *strs; /* memory block ctd, the strings */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue