mirror of
https://github.com/lua/lua
synced 2025-02-23 16:44:14 +03:00
reentrant implementation of garbage collection
This commit is contained in:
parent
9d801f43d4
commit
ed9be5e1f0
49
lgc.c
49
lgc.c
@ -136,6 +136,8 @@ static void markudet (lua_State *L, GCState *st) {
|
||||
Udata *u;
|
||||
for (u = G(L)->rootudata; u; u = u->uv.next)
|
||||
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 *curr;
|
||||
Udata *collected = NULL;
|
||||
Udata *collected = NULL; /* to collect udata with gc event */
|
||||
Udata **lastcollected = &collected;
|
||||
while ((curr = *p) != NULL) {
|
||||
if (isudmarked(curr)) {
|
||||
unmarkud(curr);
|
||||
p = &curr->uv.next;
|
||||
}
|
||||
else { /* collect */
|
||||
const TObject *tm = fasttm(L, curr->uv.eventtable, TM_GC);
|
||||
else {
|
||||
*p = curr->uv.next;
|
||||
if (keep || tm != NULL) {
|
||||
curr->uv.next = collected;
|
||||
collected = curr;
|
||||
if (fasttm(L, curr->uv.eventtable, TM_GC) != NULL) { /* gc event? */
|
||||
curr->uv.next = NULL; /* link `curr' at the end of `collected' list */
|
||||
*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));
|
||||
}
|
||||
}
|
||||
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);
|
||||
L->top++; /* reserve space to keep udata while runs its gc method */
|
||||
while (c != NULL) {
|
||||
Udata *udata = c;
|
||||
c = udata->uv.next; /* remove udata from list */
|
||||
while (G(L)->tmudata != NULL) {
|
||||
Udata *udata = G(L)->tmudata;
|
||||
G(L)->tmudata = udata->uv.next; /* remove udata from list */
|
||||
udata->uv.next = G(L)->rootudata; /* resurect it */
|
||||
G(L)->rootudata = udata;
|
||||
setuvalue(L->top - 1, udata);
|
||||
@ -383,34 +388,32 @@ static void callgcTMudata (lua_State *L, Udata *c) {
|
||||
|
||||
|
||||
void luaC_callallgcTM (lua_State *L) {
|
||||
if (G(L)->rootudata) { /* avoid problems with incomplete states */
|
||||
Udata *c = collectudata(L, 1); /* collect all udata */
|
||||
callgcTMudata(L, c); /* call their GC tag methods */
|
||||
}
|
||||
lua_assert(G(L)->tmudata == NULL);
|
||||
G(L)->tmudata = G(L)->rootudata; /* all udata must be collected */
|
||||
G(L)->rootudata = NULL;
|
||||
callgcTMudata(L); /* call their GC tag methods */
|
||||
}
|
||||
|
||||
|
||||
Udata *luaC_collect (lua_State *L, int all) {
|
||||
Udata *c = collectudata(L, 0);
|
||||
void luaC_collect (lua_State *L, int all) {
|
||||
collectudata(L);
|
||||
collectstrings(L, all);
|
||||
collecttable(L);
|
||||
collectproto(L);
|
||||
collectupval(L);
|
||||
collectclosures(L);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void luaC_collectgarbage (lua_State *L) {
|
||||
Udata *c;
|
||||
GCState st;
|
||||
st.tmark = NULL;
|
||||
st.toclear = NULL;
|
||||
markall(L, &st);
|
||||
cleartables(st.toclear);
|
||||
c = luaC_collect(L, 0);
|
||||
luaC_collect(L, 0);
|
||||
checkMbuffer(L);
|
||||
G(L)->GCthreshold = 2*G(L)->nblocks; /* new threshold */
|
||||
callgcTMudata(L, c);
|
||||
callgcTMudata(L);
|
||||
}
|
||||
|
||||
|
4
lstate.c
4
lstate.c
@ -59,8 +59,9 @@ static void f_luaopen (lua_State *L, void *ud) {
|
||||
G(L)->rootproto = NULL;
|
||||
G(L)->rootcl = NULL;
|
||||
G(L)->roottable = NULL;
|
||||
G(L)->rootudata = NULL;
|
||||
G(L)->rootupval = NULL;
|
||||
G(L)->rootudata = NULL;
|
||||
G(L)->tmudata = NULL;
|
||||
G(L)->nblocks = sizeof(lua_State) + sizeof(global_State);
|
||||
luaD_init(L, so->stacksize); /* init stack */
|
||||
/* 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 */
|
||||
if (G(L)->rootudata) /* (avoid problems with incomplete states) */
|
||||
luaC_callallgcTM(L); /* call GC tag methods for all udata */
|
||||
lua_assert(G(L)->tmudata == NULL);
|
||||
luaC_collect(L, 1); /* collect all elements */
|
||||
lua_assert(G(L)->rootproto == NULL);
|
||||
lua_assert(G(L)->rootudata == NULL);
|
||||
|
3
lstate.h
3
lstate.h
@ -81,8 +81,9 @@ typedef struct global_State {
|
||||
Proto *rootproto; /* list of all prototypes */
|
||||
Closure *rootcl; /* list of all closures */
|
||||
Table *roottable; /* list of all tables */
|
||||
Udata *rootudata; /* list of all userdata */
|
||||
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 */
|
||||
} global_State;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user