Ver código fonte

reentrant implementation of garbage collection

Roberto Ierusalimschy 23 anos atrás
pai
commit
ed9be5e1f0
3 arquivos alterados com 31 adições e 25 exclusões
  1. 26 23
      lgc.c
  2. 3 1
      lstate.c
  3. 2 1
      lstate.h

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

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

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