diff --git a/lapi.c b/lapi.c index 59129f71..48993abf 100644 --- a/lapi.c +++ b/lapi.c @@ -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 ** 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 */ -#define GCscale(x) (cast(int, (x)>>10)) -#define GCunscale(x) (cast(lu_mem, x)<<10) - -#define MAX_THRESHOLD (cast(lu_mem, ~0) >> 10) - -LUA_API int lua_getgcthreshold (lua_State *L) { - int threshold; - lua_lock(L); - threshold = GCscale(G(L)->GCthreshold); - lua_unlock(L); - return threshold; -} - -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 int lua_gc (lua_State *L, int what, int data) { + global_State *g = G(L); + switch (what) { + case LUA_GCSTOP: { + g->GCthreshold = MAXLMEM; + return 0; + } + case LUA_GCRESTART: { + g->GCthreshold = g->nblocks; + return 0; + } + case LUA_GCCOLLECT: { + lua_lock(L); + luaC_fullgc(L); + lua_unlock(L); + 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 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); -} /* diff --git a/lbaselib.c b/lbaselib.c index f59e6460..009db94b 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -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 ** See Copyright Notice in lua.h */ @@ -186,14 +186,31 @@ static int luaB_rawset (lua_State *L) { static int luaB_gcinfo (lua_State *L) { lua_pushinteger(L, lua_getgccount(L)); - lua_pushinteger(L, lua_getgcthreshold(L)); - return 2; + return 1; } static int luaB_collectgarbage (lua_State *L) { - lua_setgcthreshold(L, luaL_optint(L, 1, 0)); - return 0; + static const char *const opts[] = {"stop", "restart", "collect", "count", + 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) { const char *fname = luaL_optstring(L, 1, NULL); - int status = luaL_loadfile(L, fname); - if (status != 0) lua_error(L); + int n = lua_gettop(L); + if (luaL_loadfile(L, fname) != 0) lua_error(L); 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); lua_newtable(L); lua_setglobal(L, REQTAB); - return 0; + return 2; } diff --git a/lgc.c b/lgc.c index ae5cd686..0f34b099 100644 --- a/lgc.c +++ b/lgc.c @@ -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 ** See Copyright Notice in lua.h */ @@ -23,6 +23,8 @@ #define GCSTEPSIZE (40*sizeof(TValue)) +#define GCFREECOST (sizeof(TValue)/2) +#define GCSWEEPCOST sizeof(TValue) #define gray2black(x) setbit((x)->gch.marked, BLACKBIT) @@ -51,10 +53,6 @@ #define markvalue(g,o) { checkconsistency(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))) \ reallymarkobject(g, obj2gco(t)); } @@ -214,8 +212,8 @@ static int traversetable (global_State *g, Table *h) { Node *n = gnode(h, i); if (!ttisnil(gval(n))) { lua_assert(!ttisnil(gkey(n))); - condmarkobject(g, gkey(n), !weakkey); - condmarkobject(g, gval(n), !weakvalue); + if (!weakkey) markvalue(g, gkey(n)); + if (!weakvalue) markvalue(g, gval(n)); } } return weakkey || weakvalue; @@ -444,18 +442,19 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, int all, int dead = otherwhite(g); while ((curr = *p) != NULL) { int mark = curr->gch.marked; - lim -= objsize(curr); if (!all && (!(mark & dead) || testbit(mark, FIXEDBIT))) { makewhite(g, curr); if (curr->gch.tt == LUA_TTHREAD) sweepupvalues(g, gco2th(curr)); p = &curr->gch.next; + lim -= GCSWEEPCOST; } else { *p = curr->gch.next; if (curr == g->rootgc) /* is the first element of the list? */ g->rootgc = curr->gch.next; /* adjust first */ freeobj(L, curr); + lim -= GCFREECOST; } 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); - l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * 2; -luaC_checkall(L); switch (g->gcstate) { case GCSpropagate: { if (g->gray) - lim = propagatemarks(g, lim); + return propagatemarks(g, lim); else { /* no more `gray' objects */ atomic(L); /* finish mark phase */ - lim = 0; + return 0; } - break; } case GCSsweepstring: { lim = sweepstrings(L, 0, lim); @@ -603,7 +599,7 @@ luaC_checkall(L); g->sweepstrgc = 0; g->gcstate = GCSsweep; /* end sweep-string phase */ } - break; + return lim; } case GCSsweep: { g->sweepgc = sweeplist(L, g->sweepgc, 0, &lim); @@ -612,27 +608,45 @@ luaC_checkall(L); sweepupvalues(g, g->mainthread); g->gcstate = GCSfinalize; /* end sweep phase */ } - break; + return lim; } case GCSfinalize: { - if (g->tmudata) { + if (g->tmudata) GCTM(L); - lim = 0; - } else /* no more `udata' to finalize */ 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; -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) { global_State *g = G(L); lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); + lua_assert(g->gcstate != GCSfinalize); if (g->gcstate != GCSpropagate) /* sweeping phases? */ black2gray(o); /* just mark as gray to avoid other barriers */ else /* breaking invariant! */ diff --git a/lgc.h b/lgc.h index a6901076..eae99a98 100644 --- a/lgc.h +++ b/lgc.h @@ -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 ** 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_sweepall (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_barrierf (lua_State *L, GCObject *o, GCObject *v); diff --git a/lua.h b/lua.h index 4f2f256d..1bf74610 100644 --- a/lua.h +++ b/lua.h @@ -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 ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** 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); /* -** garbage-collection functions +** garbage-collection function and options */ -LUA_API int lua_getgcthreshold (lua_State *L); -LUA_API int lua_getgccount (lua_State *L); -LUA_API void lua_setgcthreshold (lua_State *L, int newthreshold); + +#define LUA_GCSTOP 0 +#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 @@ -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_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) + /* compatibility with ref system */