reentrant implementation of garbage collection

This commit is contained in:
Roberto Ierusalimschy
2001-12-11 14:52:57 -02:00
parent 9d801f43d4
commit ed9be5e1f0
3 changed files with 31 additions and 25 deletions

49
lgc.c
View File

@@ -136,6 +136,8 @@ static void markudet (lua_State *L, GCState *st) {
Udata *u; Udata *u;
for (u = G(L)->rootudata; u; u = u->uv.next) for (u = G(L)->rootudata; u; u = u->uv.next)
marktable(st, u->uv.eventtable); marktable(st, u->uv.eventtable);
for (u = G(L)->tmudata; u; u = u->uv.next)
marktable(st, u->uv.eventtable);
} }
@@ -290,27 +292,30 @@ static void collecttable (lua_State *L) {
} }
static Udata *collectudata (lua_State *L, int keep) { static void collectudata (lua_State *L) {
Udata **p = &G(L)->rootudata; Udata **p = &G(L)->rootudata;
Udata *curr; Udata *curr;
Udata *collected = NULL; Udata *collected = NULL; /* to collect udata with gc event */
Udata **lastcollected = &collected;
while ((curr = *p) != NULL) { while ((curr = *p) != NULL) {
if (isudmarked(curr)) { if (isudmarked(curr)) {
unmarkud(curr); unmarkud(curr);
p = &curr->uv.next; p = &curr->uv.next;
} }
else { /* collect */ else {
const TObject *tm = fasttm(L, curr->uv.eventtable, TM_GC);
*p = curr->uv.next; *p = curr->uv.next;
if (keep || tm != NULL) { if (fasttm(L, curr->uv.eventtable, TM_GC) != NULL) { /* gc event? */
curr->uv.next = collected; curr->uv.next = NULL; /* link `curr' at the end of `collected' list */
collected = curr; *lastcollected = curr;
lastcollected = &curr->uv.next;
} }
else /* no gc action; delete udata */ else /* no gc event; delete udata */
luaM_free(L, curr, sizeudata(curr->uv.len)); luaM_free(L, curr, sizeudata(curr->uv.len));
} }
} }
return collected; /* insert collected udata with gc event into `tmudata' list */
*lastcollected = G(L)->tmudata;
G(L)->tmudata = collected;
} }
@@ -365,12 +370,12 @@ static void callgcTM (lua_State *L, Udata *udata) {
} }
static void callgcTMudata (lua_State *L, Udata *c) { static void callgcTMudata (lua_State *L) {
luaD_checkstack(L, 3); luaD_checkstack(L, 3);
L->top++; /* reserve space to keep udata while runs its gc method */ L->top++; /* reserve space to keep udata while runs its gc method */
while (c != NULL) { while (G(L)->tmudata != NULL) {
Udata *udata = c; Udata *udata = G(L)->tmudata;
c = udata->uv.next; /* remove udata from list */ G(L)->tmudata = udata->uv.next; /* remove udata from list */
udata->uv.next = G(L)->rootudata; /* resurect it */ udata->uv.next = G(L)->rootudata; /* resurect it */
G(L)->rootudata = udata; G(L)->rootudata = udata;
setuvalue(L->top - 1, udata); setuvalue(L->top - 1, udata);
@@ -383,34 +388,32 @@ static void callgcTMudata (lua_State *L, Udata *c) {
void luaC_callallgcTM (lua_State *L) { void luaC_callallgcTM (lua_State *L) {
if (G(L)->rootudata) { /* avoid problems with incomplete states */ lua_assert(G(L)->tmudata == NULL);
Udata *c = collectudata(L, 1); /* collect all udata */ G(L)->tmudata = G(L)->rootudata; /* all udata must be collected */
callgcTMudata(L, c); /* call their GC tag methods */ G(L)->rootudata = NULL;
} callgcTMudata(L); /* call their GC tag methods */
} }
Udata *luaC_collect (lua_State *L, int all) { void luaC_collect (lua_State *L, int all) {
Udata *c = collectudata(L, 0); collectudata(L);
collectstrings(L, all); collectstrings(L, all);
collecttable(L); collecttable(L);
collectproto(L); collectproto(L);
collectupval(L); collectupval(L);
collectclosures(L); collectclosures(L);
return c;
} }
void luaC_collectgarbage (lua_State *L) { void luaC_collectgarbage (lua_State *L) {
Udata *c;
GCState st; GCState st;
st.tmark = NULL; st.tmark = NULL;
st.toclear = NULL; st.toclear = NULL;
markall(L, &st); markall(L, &st);
cleartables(st.toclear); cleartables(st.toclear);
c = luaC_collect(L, 0); luaC_collect(L, 0);
checkMbuffer(L); checkMbuffer(L);
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */ G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
callgcTMudata(L, c); callgcTMudata(L);
} }

View File

@@ -59,8 +59,9 @@ static void f_luaopen (lua_State *L, void *ud) {
G(L)->rootproto = NULL; G(L)->rootproto = NULL;
G(L)->rootcl = NULL; G(L)->rootcl = NULL;
G(L)->roottable = NULL; G(L)->roottable = NULL;
G(L)->rootudata = NULL;
G(L)->rootupval = NULL; G(L)->rootupval = NULL;
G(L)->rootudata = NULL;
G(L)->tmudata = NULL;
G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); G(L)->nblocks = sizeof(lua_State) + sizeof(global_State);
luaD_init(L, so->stacksize); /* init stack */ luaD_init(L, so->stacksize); /* init stack */
/* create default event table with a dummy table, and then close the loop */ /* create default event table with a dummy table, and then close the loop */
@@ -118,6 +119,7 @@ static void close_state (lua_State *L, lua_State *OL) {
else if (G(L)) { /* last thread; close global state */ else if (G(L)) { /* last thread; close global state */
if (G(L)->rootudata) /* (avoid problems with incomplete states) */ if (G(L)->rootudata) /* (avoid problems with incomplete states) */
luaC_callallgcTM(L); /* call GC tag methods for all udata */ luaC_callallgcTM(L); /* call GC tag methods for all udata */
lua_assert(G(L)->tmudata == NULL);
luaC_collect(L, 1); /* collect all elements */ luaC_collect(L, 1); /* collect all elements */
lua_assert(G(L)->rootproto == NULL); lua_assert(G(L)->rootproto == NULL);
lua_assert(G(L)->rootudata == NULL); lua_assert(G(L)->rootudata == NULL);

View File

@@ -81,8 +81,9 @@ typedef struct global_State {
Proto *rootproto; /* list of all prototypes */ Proto *rootproto; /* list of all prototypes */
Closure *rootcl; /* list of all closures */ Closure *rootcl; /* list of all closures */
Table *roottable; /* list of all tables */ Table *roottable; /* list of all tables */
Udata *rootudata; /* list of all userdata */
UpVal *rootupval; /* list of closed up values */ UpVal *rootupval; /* list of closed up values */
Udata *rootudata; /* list of all userdata */
Udata *tmudata; /* list of userdata to be GC */
TString *tmname[TM_N]; /* array with tag-method names */ TString *tmname[TM_N]; /* array with tag-method names */
} global_State; } global_State;