소스 검색

userdata with finalizers are kept in a separated list ('udgc'), instead
of at the end of 'rootgc' (which was renamed to 'allgc', as it is not
"root" in the usual meaning for collectors)

Roberto Ierusalimschy 15 년 전
부모
커밋
4433dbb5f5
5개의 변경된 파일48개의 추가작업 그리고 44개의 파일을 삭제
  1. 30 26
      lgc.c
  2. 6 6
      lgc.h
  3. 3 2
      lstate.c
  4. 5 6
      lstate.h
  5. 4 4
      ltests.c

+ 30 - 26
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.68 2010/03/22 18:28:03 roberto Exp $
+** $Id: lgc.c,v 2.69 2010/03/23 20:16:06 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -33,8 +33,10 @@
 
 #define maskcolors	(~(bitmask(BLACKBIT)|WHITEBITS))
 
-#define makewhite(g,x)	\
- (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g)))
+#define makewhitew(w,x)	\
+ (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | (w)))
+
+#define makewhite(g,x)	makewhitew(luaC_white(g), x)
 
 #define white2gray(x)	resetbits(gch(x)->marked, WHITEBITS)
 #define black2gray(x)	resetbit(gch(x)->marked, BLACKBIT)
@@ -127,7 +129,7 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
   global_State *g = G(L);
   GCObject *o = obj2gco(cast(char *, luaM_newobject(L, tt, sz)) + offset);
   if (list == NULL)
-    list = &g->rootgc;  /* standard list for collectable objects */
+    list = &g->allgc;  /* standard list for collectable objects */
   gch(o)->marked = luaC_white(g);
   gch(o)->tt = tt;
   gch(o)->next = *list;
@@ -139,8 +141,8 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
 void luaC_linkupval (lua_State *L, UpVal *uv) {
   global_State *g = G(L);
   GCObject *o = obj2gco(uv);
-  gch(o)->next = g->rootgc;  /* link upvalue into `rootgc' list */
-  g->rootgc = o;
+  gch(o)->next = g->allgc;  /* link upvalue into `allgc' list */
+  g->allgc = o;
   if (isgray(o)) {
     if (g->gcstate == GCSpropagate) {
       gray2black(o);  /* closed upvalues need barrier */
@@ -549,8 +551,9 @@ static void sweepthread (lua_State *L, lua_State *L1, int alive) {
 static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
   GCObject *curr;
   global_State *g = G(L);
-  int deadmask = otherwhite(g);
   int gckind = g->gckind;
+  int deadmask = otherwhite(g);
+  int white = luaC_white(g);
   while ((curr = *p) != NULL && count-- > 0) {
     int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask;
     if (gch(curr)->tt == LUA_TTHREAD)
@@ -559,7 +562,7 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
       lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT));
       /* in generational mode all live objects are kept black, which
          means they grow to old generation */
-      if (gckind != KGC_GEN) makewhite(g, curr);
+      if (gckind != KGC_GEN) makewhitew(white, curr);
       p = &gch(curr)->next;
     }
     else {  /* must erase `curr' */
@@ -597,8 +600,8 @@ static void checkSizes (lua_State *L) {
 static Udata *udata2finalize (global_State *g) {
   GCObject *o = g->tobefnz;  /* get first element */
   g->tobefnz = gch(o)->next;  /* remove it from 'tobefnz' list */
-  gch(o)->next = g->rootgc;  /* return it to `root' list */
-  g->rootgc = o;
+  gch(o)->next = g->allgc;  /* return it to 'allgc' list */
+  g->allgc = o;
   lua_assert(isfinalized(gch(o)));
   resetbit(gch(o)->marked, SEPARATED);  /* mark it as such */
   makewhite(g, o);
@@ -643,7 +646,7 @@ static void GCTM (lua_State *L, int propagateerrors) {
 /* move 'dead' udata that need finalization to list 'tobefnz' */
 void luaC_separateudata (lua_State *L, int all) {
   global_State *g = G(L);
-  GCObject **p = &g->mainthread->next;
+  GCObject **p = &g->udgc;
   GCObject *curr;
   GCObject **lastnext = &g->tobefnz;
   /* find last 'next' field in 'tobefnz' list (to insert elements in its end) */
@@ -655,7 +658,7 @@ void luaC_separateudata (lua_State *L, int all) {
       p = &gch(curr)->next;  /* don't bother with it */
     else {
       l_setbit(gch(curr)->marked, FINALIZEDBIT); /* won't be finalized again */
-      *p = gch(curr)->next;  /* remove 'curr' from 'rootgc' list */
+      *p = gch(curr)->next;  /* remove 'curr' from 'udgc' list */
       /* link 'curr' at the end of 'tobefnz' list */
       gch(curr)->next = *lastnext;
       *lastnext = curr;
@@ -671,13 +674,12 @@ void luaC_checkfinalizer (lua_State *L, Udata *u) {
       isfinalized(&u->uv) ||                        /* ... or is finalized... */
       gfasttm(g, u->uv.metatable, TM_GC) == NULL)  /* or has no finalization? */
     return;  /* nothing to be done */
-  else {  /* move 'u' to 2nd part of root list */
+  else {  /* move 'u' to 'udgc' list */
     GCObject **p;
-    for (p = &g->rootgc; *p != obj2gco(u); p = &gch(*p)->next)
-      lua_assert(*p != obj2gco(g->mainthread));  /* 'u' must be in this list */
+    for (p = &g->allgc; *p != obj2gco(u); p = &gch(*p)->next) ;
     *p = u->uv.next;  /* remove 'u' from root list */
-    u->uv.next = g->mainthread->next;  /* re-link it in list */
-    g->mainthread->next = obj2gco(u);
+    u->uv.next = g->udgc;  /* re-link it in list */
+    g->udgc = obj2gco(u);
     l_setbit(u->uv.marked, SEPARATED);  /* mark it as such */
   }
 }
@@ -697,8 +699,9 @@ void luaC_freeallobjects (lua_State *L) {
   while (g->tobefnz) GCTM(L, 0);  /* Call all pending finalizers */
   /* following "white" makes all objects look dead */
   g->currentwhite = WHITEBITS | bitmask(SFIXEDBIT);
-  sweepwholelist(L, &g->rootgc);
-  lua_assert(g->rootgc == obj2gco(g->mainthread) &&
+  sweepwholelist(L, &g->udgc);
+  sweepwholelist(L, &g->allgc);
+  lua_assert(g->allgc == obj2gco(g->mainthread) &&
              g->mainthread->next == NULL);
   for (i = 0; i < g->strt.size; i++)  /* free all string lists */
     sweepwholelist(L, &g->strt.hash[i]);
@@ -761,19 +764,21 @@ static l_mem singlestep (lua_State *L) {
         return GCSWEEPCOST;
       }
       else {  /* nothing more to sweep */
-        g->sweepgc = &g->rootgc;
-        g->gcstate = GCSsweep;  /* sweep all other objects */
+        g->sweepgc = &g->udgc;  /* sweep all userdata */
+        g->gcstate = GCSsweepudata;
+        checkSizes(L);
         return 0;
       }
     }
+    case GCSsweepudata:
     case GCSsweep: {
       if (*g->sweepgc) {
         g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
         return GCSWEEPMAX*GCSWEEPCOST;
       }
-      else {  /* nothing more to sweep */
-        checkSizes(L);
-        g->gcstate = GCSfinalize;  /* end sweep phase */
+      else {  /* go to next phase */
+        g->sweepgc = &g->allgc;  /* useless (but harmless) in GCSsweep case */
+        g->gcstate = (g->gcstate == GCSsweep) ? GCSfinalize : GCSsweep;
         return 0;
       }
     }
@@ -856,8 +861,7 @@ void luaC_fullgc (lua_State *L, int isemergency) {
     g->gcstate = GCSsweepstring;
   }
   /* finish any pending sweep phase */
-  luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep));
-  lua_assert(g->gcstate == GCSpause || g->gcstate == GCSfinalize);
+  luaC_runtilstate(L, bit2mask(GCSpause, GCSfinalize));
   g->gcstate = GCSpause;  /* start a new collection */
   /* run collector up to finalizers */
   luaC_runtilstate(L, bitmask(GCSfinalize));

+ 6 - 6
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.26 2009/12/11 21:31:14 roberto Exp roberto $
+** $Id: lgc.h,v 2.27 2009/12/16 16:42:58 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -18,8 +18,9 @@
 #define GCSpropagate	1
 #define GCSatomic	2
 #define GCSsweepstring	3
-#define GCSsweep	4
-#define GCSfinalize	5
+#define GCSsweepudata	4
+#define GCSsweep	5
+#define GCSfinalize	6
 
 
 
@@ -45,12 +46,10 @@
 ** bit 1 - object is white (type 1)
 ** bit 2 - object is black
 ** bit 3 - for userdata: has been finalized
-** bit 4 - for userdata: it's in 2nd part of rootgc list or in tobefnz
+** bit 4 - for userdata: it's in 'udgc' list or in 'tobefnz'
 ** bit 5 - object is fixed (should not be collected)
 ** bit 6 - object is "super" fixed (only the main thread)
 */
-
-
 #define WHITE0BIT	0
 #define WHITE1BIT	1
 #define BLACKBIT	2
@@ -58,6 +57,7 @@
 #define SEPARATED	4
 #define FIXEDBIT	5
 #define SFIXEDBIT	6
+
 #define WHITEBITS	bit2mask(WHITE0BIT, WHITE1BIT)
 
 

+ 3 - 2
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.70 2010/03/19 21:04:17 roberto Exp roberto $
+** $Id: lstate.c,v 2.71 2010/03/22 17:45:55 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -264,7 +264,8 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   g->panic = NULL;
   g->version = lua_version(NULL);
   g->gcstate = GCSpause;
-  g->rootgc = obj2gco(L);
+  g->allgc = obj2gco(L);
+  g->udgc = NULL;
   g->tobefnz = NULL;
   g->totalbytes = sizeof(LG);
   g->gcpause = LUAI_GCPAUSE;

+ 5 - 6
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.54 2010/03/13 15:55:42 roberto Exp roberto $
+** $Id: lstate.h,v 2.55 2010/03/22 18:28:03 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -19,7 +19,7 @@
 ** Some notes about garbage-collected objects:  All objects in Lua must
 ** be kept somehow accessible until being freed.
 **
-** Lua keeps most objects linked in list g->rootgc. The link uses field
+** Lua keeps most objects linked in list g->allgc. The link uses field
 ** 'next' of the CommonHeader.
 **
 ** Strings are kept in several lists headed by the array g->strt.hash.
@@ -32,9 +32,7 @@
 ** when traversing the respective threads, but the thread may already be
 ** dead, while the upvalue is still accessible through closures.)
 **
-** Userdata with finalizers are kept in the list g->rootgc, but after
-** the mainthread, which should be otherwise the last element in the
-** list, as it was the first one inserted there.
+** Userdata with finalizers are kept in the list g->udgc.
 **
 ** The list g->tobefnz links all userdata being finalized.
 
@@ -124,7 +122,8 @@ typedef struct global_State {
   lu_byte gcstate;  /* state of garbage collector */
   lu_byte gckind;  /* kind of GC running */
   int sweepstrgc;  /* position of sweep in `strt' */
-  GCObject *rootgc;  /* list of all collectable objects */
+  GCObject *allgc;  /* list of all collectable objects */
+  GCObject *udgc;  /* list of collectable userdata with finalizers */
   GCObject **sweepgc;  /* current position of sweep */
   GCObject *gray;  /* list of gray objects */
   GCObject *grayagain;  /* list of objects to be traversed atomically */

+ 4 - 4
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.86 2009/12/22 15:32:50 roberto Exp roberto $
+** $Id: ltests.c,v 2.87 2010/01/13 16:18:25 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -188,7 +188,7 @@ static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
 static void printobj (global_State *g, GCObject *o) {
   int i = 0;
   GCObject *p;
-  for (p = g->rootgc; p != o && p != NULL; p = gch(p)->next) i++;
+  for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++;
   if (p == NULL) i = -1;
   printf("%d:%s(%p)-%c(%02X)", i, typename(gch(o)->tt), (void *)o,
            isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked);
@@ -375,12 +375,12 @@ int lua_checkmemory (lua_State *L) {
   checkliveness(g, &g->l_registry);
   lua_assert(!isdead(g, obj2gco(g->l_gt)));
   checkstack(g, g->mainthread);
-  for (o = g->rootgc; o != obj2gco(g->mainthread); o = gch(o)->next) {
+  for (o = g->allgc; o != obj2gco(g->mainthread); o = gch(o)->next) {
     lua_assert(!testbits(o->gch.marked, bit2mask(SEPARATED, SFIXEDBIT)));
     checkobject(g, o);
   }
   lua_assert(testbit(o->gch.marked, SFIXEDBIT));
-  for (o = gch(o)->next; o != NULL; o = gch(o)->next) {
+  for (o = g->udgc; o != NULL; o = gch(o)->next) {
     lua_assert(gch(o)->tt == LUA_TUSERDATA &&
                !isdead(g, o) &&
                testbit(o->gch.marked, SEPARATED));