Browse Source

new (temporary?) API for garbage collector

Roberto Ierusalimschy 21 years ago
parent
commit
b876ec61c0
5 changed files with 101 additions and 67 deletions
  1. 25 30
      lapi.c
  2. 26 9
      lbaselib.c
  3. 36 22
      lgc.c
  4. 2 1
      lgc.h
  5. 12 5
      lua.h

+ 25 - 30
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);
-}
 
 
 /*

+ 26 - 9
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;
 }
 

+ 36 - 22
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! */

+ 2 - 1
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);
 

+ 12 - 5
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:[email protected]
@@ -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 */