new (temporary?) API for garbage collector

This commit is contained in:
Roberto Ierusalimschy 2004-03-09 14:34:35 -03:00
parent 898e8a6794
commit b876ec61c0
5 changed files with 101 additions and 67 deletions

51
lapi.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lapi.c,v 2.2 2004/01/15 12:40:26 roberto Exp roberto $ ** $Id: lapi.c,v 2.3 2004/02/20 16:01:05 roberto Exp roberto $
** Lua API ** Lua API
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -807,39 +807,34 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) {
/* /*
** Garbage-collection functions ** Garbage-collection function
*/ */
/* GC values are expressed in Kbytes: #bytes/2^10 */ LUA_API int lua_gc (lua_State *L, int what, int data) {
#define GCscale(x) (cast(int, (x)>>10)) global_State *g = G(L);
#define GCunscale(x) (cast(lu_mem, x)<<10) switch (what) {
case LUA_GCSTOP: {
#define MAX_THRESHOLD (cast(lu_mem, ~0) >> 10) g->GCthreshold = MAXLMEM;
return 0;
LUA_API int lua_getgcthreshold (lua_State *L) { }
int threshold; case LUA_GCRESTART: {
g->GCthreshold = g->nblocks;
return 0;
}
case LUA_GCCOLLECT: {
lua_lock(L); lua_lock(L);
threshold = GCscale(G(L)->GCthreshold); luaC_fullgc(L);
lua_unlock(L); lua_unlock(L);
return threshold; return 0;
}
case LUA_GCCOUNT: {
/* GC values are expressed in Kbytes: #bytes/2^10 */
return cast(int, g->nblocks >> 10);
}
default: return -1; /* invalid option */
}
} }
LUA_API int lua_getgccount (lua_State *L) {
int count;
lua_lock(L);
count = GCscale(G(L)->nblocks);
lua_unlock(L);
return count;
}
LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold) {
lua_lock(L);
if (cast(lu_mem, newthreshold) > MAX_THRESHOLD)
newthreshold = cast(int, MAX_THRESHOLD);
G(L)->GCthreshold = GCunscale(newthreshold);
luaC_checkGC(L);
lua_unlock(L);
}
/* /*

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lbaselib.c,v 1.138 2003/11/11 16:34:17 roberto Exp roberto $ ** $Id: lbaselib.c,v 1.139 2003/12/09 16:55:43 roberto Exp roberto $
** Basic library ** Basic library
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -186,14 +186,31 @@ static int luaB_rawset (lua_State *L) {
static int luaB_gcinfo (lua_State *L) { static int luaB_gcinfo (lua_State *L) {
lua_pushinteger(L, lua_getgccount(L)); lua_pushinteger(L, lua_getgccount(L));
lua_pushinteger(L, lua_getgcthreshold(L)); return 1;
return 2;
} }
static int luaB_collectgarbage (lua_State *L) { static int luaB_collectgarbage (lua_State *L) {
lua_setgcthreshold(L, luaL_optint(L, 1, 0)); static const char *const opts[] = {"stop", "restart", "collect", "count",
return 0; NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART,
LUA_GCCOLLECT, LUA_GCCOUNT};
int o;
int ex;
#if 1
if (lua_isnumber(L, 1)) {
int v = lua_tointeger(L, 1);
lua_settop(L, 0);
if (v == 0) lua_pushstring(L, "collect");
else if (v >= 10000) lua_pushstring(L, "stop");
else lua_pushstring(L, "restart");
}
#endif
o = luaL_findstring(luaL_optstring(L, 1, "collect"), opts);
ex = luaL_optint(L, 2, 0);
luaL_argcheck(L, o >= 0, 1, "invalid option");
lua_pushinteger(L, lua_gc(L, optsnum[o], ex));
return 1;
} }
@ -311,10 +328,10 @@ static int luaB_load (lua_State *L) {
static int luaB_dofile (lua_State *L) { static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL); const char *fname = luaL_optstring(L, 1, NULL);
int status = luaL_loadfile(L, fname); int n = lua_gettop(L);
if (status != 0) lua_error(L); if (luaL_loadfile(L, fname) != 0) lua_error(L);
lua_call(L, 0, LUA_MULTRET); lua_call(L, 0, LUA_MULTRET);
return lua_gettop(L) - 1; return lua_gettop(L) - n;
} }
@ -710,6 +727,6 @@ LUALIB_API int luaopen_base (lua_State *L) {
luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0); luaL_openlib(L, LUA_COLIBNAME, co_funcs, 0);
lua_newtable(L); lua_newtable(L);
lua_setglobal(L, REQTAB); lua_setglobal(L, REQTAB);
return 0; return 2;
} }

58
lgc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ ** $Id: lgc.c,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -23,6 +23,8 @@
#define GCSTEPSIZE (40*sizeof(TValue)) #define GCSTEPSIZE (40*sizeof(TValue))
#define GCFREECOST (sizeof(TValue)/2)
#define GCSWEEPCOST sizeof(TValue)
#define gray2black(x) setbit((x)->gch.marked, BLACKBIT) #define gray2black(x) setbit((x)->gch.marked, BLACKBIT)
@ -51,10 +53,6 @@
#define markvalue(g,o) { checkconsistency(o); \ #define markvalue(g,o) { checkconsistency(o); \
if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); } if (iscollectable(o) && iswhite(gcvalue(o))) reallymarkobject(g,gcvalue(o)); }
#define condmarkobject(g,o,c) { checkconsistency(o); \
if (iscollectable(o) && iswhite(gcvalue(o)) && (c)) \
reallymarkobject(g,gcvalue(o)); }
#define markobject(g,t) { if (iswhite(obj2gco(t))) \ #define markobject(g,t) { if (iswhite(obj2gco(t))) \
reallymarkobject(g, obj2gco(t)); } reallymarkobject(g, obj2gco(t)); }
@ -214,8 +212,8 @@ static int traversetable (global_State *g, Table *h) {
Node *n = gnode(h, i); Node *n = gnode(h, i);
if (!ttisnil(gval(n))) { if (!ttisnil(gval(n))) {
lua_assert(!ttisnil(gkey(n))); lua_assert(!ttisnil(gkey(n)));
condmarkobject(g, gkey(n), !weakkey); if (!weakkey) markvalue(g, gkey(n));
condmarkobject(g, gval(n), !weakvalue); if (!weakvalue) markvalue(g, gval(n));
} }
} }
return weakkey || weakvalue; return weakkey || weakvalue;
@ -444,18 +442,19 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all,
int dead = otherwhite(g); int dead = otherwhite(g);
while ((curr = *p) != NULL) { while ((curr = *p) != NULL) {
int mark = curr->gch.marked; int mark = curr->gch.marked;
lim -= objsize(curr);
if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) {
makewhite(g, curr); makewhite(g, curr);
if (curr->gch.tt == LUA_TTHREAD) if (curr->gch.tt == LUA_TTHREAD)
sweepupvalues(g, gco2th(curr)); sweepupvalues(g, gco2th(curr));
p = &curr->gch.next; p = &curr->gch.next;
lim -= GCSWEEPCOST;
} }
else { else {
*p = curr->gch.next; *p = curr->gch.next;
if (curr == g->rootgc) /* is the first element of the list? */ if (curr == g->rootgc) /* is the first element of the list? */
g->rootgc = curr->gch.next; /* adjust first */ g->rootgc = curr->gch.next; /* adjust first */
freeobj(L, curr); freeobj(L, curr);
lim -= GCFREECOST;
} }
if (lim <= 0) break; if (lim <= 0) break;
} }
@ -583,19 +582,16 @@ static void atomic (lua_State *L) {
} }
void luaC_step (lua_State *L) { static l_mem singlestep (lua_State *L, l_mem lim) {
global_State *g = G(L); global_State *g = G(L);
l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2;
luaC_checkall(L);
switch (g->gcstate) { switch (g->gcstate) {
case GCSpropagate: { case GCSpropagate: {
if (g->gray) if (g->gray)
lim = propagatemarks(g, lim); return propagatemarks(g, lim);
else { /* no more `gray' objects */ else { /* no more `gray' objects */
atomic(L); /* finish mark phase */ atomic(L); /* finish mark phase */
lim = 0; return 0;
} }
break;
} }
case GCSsweepstring: { case GCSsweepstring: {
lim = sweepstrings(L, 0, lim); lim = sweepstrings(L, 0, lim);
@ -603,7 +599,7 @@ luaC_checkall(L);
g->sweepstrgc = 0; g->sweepstrgc = 0;
g->gcstate = GCSsweep; /* end sweep-string phase */ g->gcstate = GCSsweep; /* end sweep-string phase */
} }
break; return lim;
} }
case GCSsweep: { case GCSsweep: {
g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim);
@ -612,27 +608,45 @@ luaC_checkall(L);
sweepupvalues(g, g->mainthread); sweepupvalues(g, g->mainthread);
g->gcstate = GCSfinalize; /* end sweep phase */ g->gcstate = GCSfinalize; /* end sweep phase */
} }
break; return lim;
} }
case GCSfinalize: { case GCSfinalize: {
if (g->tmudata) { if (g->tmudata)
GCTM(L); GCTM(L);
lim = 0;
}
else /* no more `udata' to finalize */ else /* no more `udata' to finalize */
markroot(L); /* may restart collection */ markroot(L); /* may restart collection */
break; return 0;
} }
default: lua_assert(0); default: lua_assert(0); return 0; /* to avoid warnings */
} }
}
void luaC_step (lua_State *L) {
global_State *g = G(L);
l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2;
/*printf("+ %d %lu %lu %ld\n", g->gcstate, g->nblocks, g->GCthreshold, lim);*/
while (lim > 0) lim = singlestep(L, lim);
g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2; g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/2;
luaC_checkall(L); /*printf("- %d %lu %lu %ld\n", g->gcstate, g->nblocks, g->GCthreshold, lim);*/
lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/2);
}
void luaC_fullgc (lua_State *L) {
global_State *g = G(L);
while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM);
markroot(L);
while (g->gcstate != GCSfinalize) singlestep(L, MAXLMEM);
luaC_callGCTM(L); /* call finalizers */
g->GCthreshold = g->nblocks + GCSTEPSIZE;
} }
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o));
lua_assert(g->gcstate != GCSfinalize);
if (g->gcstate != GCSpropagate) /* sweeping phases? */ if (g->gcstate != GCSpropagate) /* sweeping phases? */
black2gray(o); /* just mark as gray to avoid other barriers */ black2gray(o); /* just mark as gray to avoid other barriers */
else /* breaking invariant! */ else /* breaking invariant! */

3
lgc.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.2 2003/12/12 18:29:34 roberto Exp roberto $ ** $Id: lgc.h,v 2.3 2004/02/16 19:09:52 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -85,6 +85,7 @@ size_t luaC_separateudata (lua_State *L, int all);
void luaC_callGCTM (lua_State *L); void luaC_callGCTM (lua_State *L);
void luaC_sweepall (lua_State *L); void luaC_sweepall (lua_State *L);
void luaC_step (lua_State *L); void luaC_step (lua_State *L);
void luaC_fullgc (lua_State *L);
void luaC_link (lua_State *L, GCObject *o, lu_byte tt); void luaC_link (lua_State *L, GCObject *o, lu_byte tt);
void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v); void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v);

17
lua.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lua.h,v 1.185 2003/11/05 11:59:14 roberto Exp roberto $ ** $Id: lua.h,v 1.186 2003/12/10 11:04:54 roberto Exp roberto $
** Lua - An Extensible Extension Language ** Lua - An Extensible Extension Language
** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
** http://www.lua.org mailto:info@lua.org ** http://www.lua.org mailto:info@lua.org
@ -221,11 +221,16 @@ LUA_API int lua_yield (lua_State *L, int nresults);
LUA_API int lua_resume (lua_State *L, int narg); LUA_API int lua_resume (lua_State *L, int narg);
/* /*
** garbage-collection functions ** garbage-collection function and options
*/ */
LUA_API int lua_getgcthreshold (lua_State *L);
LUA_API int lua_getgccount (lua_State *L); #define LUA_GCSTOP 0
LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold); #define LUA_GCRESTART 1
#define LUA_GCCOLLECT 2
#define LUA_GCCOUNT 3
LUA_API int lua_gc (lua_State *L, int what, int data);
/* /*
** miscellaneous functions ** miscellaneous functions
@ -287,6 +292,8 @@ LUA_API lua_Alloc lua_getallocf (lua_State *L, void **ud);
#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) #define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX)
#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0)
/* compatibility with ref system */ /* compatibility with ref system */