Browse Source

threads are kept in a separated GC list, linked after the main thread

Roberto Ierusalimschy 12 năm trước cách đây
mục cha
commit
dd373a8f66
5 tập tin đã thay đổi với 47 bổ sung47 xóa
  1. 12 9
      lgc.c
  2. 5 4
      lgc.h
  3. 6 14
      lstate.c
  4. 12 13
      lstate.h
  5. 12 7
      ltests.c

+ 12 - 9
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.160 2013/09/11 12:47:48 roberto Exp roberto $
+** $Id: lgc.c,v 2.161 2013/09/11 13:24:55 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -304,7 +304,7 @@ static void markbeingfnz (global_State *g) {
 ** thread.)
 */
 static void remarkupvals (global_State *g) {
-  GCObject *thread = hvalue(&g->l_registry)->next;
+  GCObject *thread = g->mainthread->next;
   for (; thread != NULL; thread = gch(thread)->next) {
     lua_assert(!isblack(thread));  /* threads are never black */
     if (!isgray(thread)) {  /* dead thread? */
@@ -933,10 +933,9 @@ static void localmarkthread (lua_State *l) {
 ** a thread)
 */
 static void localmark (global_State *g) {
-  GCObject *thread = hvalue(&g->l_registry)->next;
+  GCObject *thread = obj2gco(g->mainthread);
   for (; thread != NULL; thread = gch(thread)->next)  /* traverse all threads */
     localmarkthread(gco2th(thread));
-  localmarkthread(g->mainthread);
 }
 
 
@@ -1057,12 +1056,14 @@ void luaC_freeallobjects (lua_State *L) {
   separatetobefnz(g, 1);  /* separate all objects with finalizers */
   lua_assert(g->finobj == NULL && g->localfin == NULL);
   callallpendingfinalizers(L, 0);
+  lua_assert(g->tobefnz == NULL);
   g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */
   g->gckind = KGC_NORMAL;
+  sweepwholelist(L, &g->localgc);
   sweepwholelist(L, &g->localfin);  /* finalizers can create objs. with fins. */
   sweepwholelist(L, &g->finobj);
-  sweepwholelist(L, &g->localgc);
   sweepwholelist(L, &g->allgc);
+  sweepwholelist(L, &g->mainthread->next);
   sweepwholelist(L, &g->fixedgc);  /* collect fixed objects */
   lua_assert(g->strt.nuse == 0);
 }
@@ -1163,11 +1164,13 @@ static lu_mem singlestep (lua_State *L) {
       return sweepstep(L, g, GCSsweeptobefnz, &g->tobefnz);
     }
     case GCSsweeptobefnz: {
-      return sweepstep(L, g, GCSsweepmainth, NULL);
+      return sweepstep(L, g, GCSsweepthreads, &g->mainthread->next);
+    }
+    case GCSsweepthreads: {
+      return sweepstep(L, g, GCSsweepend, NULL);
     }
-    case GCSsweepmainth: {  /* sweep main thread */
-      GCObject *mt = obj2gco(g->mainthread);
-      sweeplist(L, &mt, 1);
+    case GCSsweepend: {
+      makewhite(g, obj2gco(g->mainthread));  /* sweep main thread */
       checkBuffer(L);
       g->gcstate = GCSpause;  /* finish collection */
       return GCSWEEPCOST;

+ 5 - 4
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.72 2013/09/11 12:26:14 roberto Exp roberto $
+** $Id: lgc.h,v 2.73 2013/09/11 12:47:48 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -43,12 +43,13 @@
 #define GCSsweepfin	4
 #define GCSsweepall	5
 #define GCSsweeptobefnz	6
-#define GCSsweepmainth	7
-#define GCSpause	8
+#define GCSsweepthreads	7
+#define GCSsweepend	8
+#define GCSpause	9
 
 
 #define issweepphase(g)  \
-	(GCSsweeplocal <= (g)->gcstate && (g)->gcstate <= GCSsweepmainth)
+	(GCSsweeplocal <= (g)->gcstate && (g)->gcstate <= GCSsweepend)
 
 
 /*

+ 6 - 14
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.111 2013/09/05 19:31:49 roberto Exp roberto $
+** $Id: lstate.c,v 2.112 2013/09/11 12:26:14 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -165,14 +165,6 @@ static void init_registry (lua_State *L, global_State *g) {
   sethvalue(L, &g->l_registry, registry);
   luaH_resize(L, registry, LUA_RIDX_LAST, 0);
   nolocal(obj2gco(registry));
-  /* registry is the first "regular" object created by a state; move it
-     from 'localgc' to 'allgc' so that it act as a "sentinel" there */
-  lua_assert(g->allgc == NULL &&
-             registry->next == NULL &&
-             g->localgc == obj2gco(registry));
-  g->allgc = g->localgc;
-  g->localgc = NULL;
-  l_setbit(registry->marked, LOCALMARK);  /* mark that it is not in 'localgc' */
   /* registry[LUA_RIDX_MAINTHREAD] = L */
   setthvalue(L, &temp, L);  /* temp = L */
   luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
@@ -243,11 +235,11 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
   luaC_checkGC(L);
   /* create new thread */
   L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l;
-  L1->marked = luaC_white(g) | bitmask(LOCALMARK) | bitmask(NOLOCALBIT);
+  L1->marked = luaC_white(g) | bit2mask(NOLOCALBIT, LOCALMARK);
   L1->tt = LUA_TTHREAD;
-  /* link it after 'l_registry' */
-  L1->next = hvalue(&g->l_registry)->next;
-  hvalue(&g->l_registry)->next = obj2gco(L1);
+  /* link it on list of threads */
+  L1->next = g->mainthread->next;
+  g->mainthread->next = obj2gco(L1);
   setthvalue(L, L->top, L1);
   api_incr_top(L);
   preinit_state(L1, g);
@@ -283,7 +275,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   L->next = NULL;
   L->tt = LUA_TTHREAD;
   g->currentwhite = bitmask(WHITE0BIT);
-  L->marked = luaC_white(g) | bitmask(NOLOCALBIT);
+  L->marked = luaC_white(g) | bit2mask(NOLOCALBIT, LOCALMARK);
   g->gckind = KGC_NORMAL;
   preinit_state(L, g);
   g->frealloc = f;

+ 12 - 13
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.93 2013/09/03 15:37:10 roberto Exp roberto $
+** $Id: lstate.h,v 2.94 2013/09/05 19:31:49 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -16,20 +16,19 @@
 
 /*
 
-** Some notes about garbage-collected objects:  All objects in Lua must
-** be kept somehow accessible until being freed.
+** Some notes about garbage-collected objects: All objects in Lua must
+** be kept somehow accessible until being freed, so all objects always
+** belong to one (and only one) of these lists, using field 'next' of
+** the 'CommonHeader' for the link:
 **
-** Lua keeps most objects linked in list g->allgc. The link uses field
-** 'next' of the CommonHeader. Threads (except the main one) ar kept
-** at the end of the 'allgc' list, after the 'l_registry' (which is
-** the first object to be added to the list).
-**
-** List 'fixedgc' keep objects that are not to be collected (currently
+** mainthread->next: all threads;
+** localgc: all local objects not marked for finalization;
+** localfin: all local objects marked for finalization;
+** allgc: all non local objects not marked for finalization;
+** finobj: all non local objects marked for finalization;
+** tobefnz: all objects ready to be finalized; 
+** fixedgc: all objects that are not to be collected (currently
 ** only small strings, such as reserved words).
-**
-** Live objects with finalizers are kept in the list g->finobj. The
-** list g->tobefnz links all objects being finalized. In particular, an
-** object has its FINALIZEDBIT set iff it is in one of these lists.
 
 */
 

+ 12 - 7
ltests.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltests.c,v 2.156 2013/09/11 12:26:14 roberto Exp roberto $
+** $Id: ltests.c,v 2.157 2013/09/11 12:47:48 roberto Exp roberto $
 ** Internal Module for Debugging of the Lua Implementation
 ** See Copyright Notice in lua.h
 */
@@ -423,7 +423,6 @@ int lua_checkmemory (lua_State *L) {
   global_State *g = G(L);
   GCObject *o;
   int maybedead;
-  int isthread;
   if (keepinvariant(g)) {
     lua_assert(!iswhite(obj2gco(g->mainthread)));
     lua_assert(!iswhite(gcvalue(&g->l_registry)));
@@ -443,14 +442,20 @@ int lua_checkmemory (lua_State *L) {
   /* check 'allgc' list */
   checkgray(g, g->allgc);
   maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSsweepall);
-  isthread = 0;  /* not traversing threads (yet) */  
   for (o = g->allgc; o != NULL; o = gch(o)->next) {
-    if (gch(o)->tt == LUA_TTHREAD) isthread = 1;  /* now travesing threads... */
-    else lua_assert(!isthread);  /* ... and only threads */
     checkobject(g, o, maybedead);
     lua_assert(!tofinalize(o) && testbit(o->gch.marked, LOCALMARK));
     lua_assert(testbit(o->gch.marked, NOLOCALBIT));
   }
+  /* check thread list */
+  checkgray(g, obj2gco(g->mainthread));
+  maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSsweepthreads);
+  for (o = obj2gco(g->mainthread); o != NULL; o = gch(o)->next) {
+    checkobject(g, o, maybedead);
+    lua_assert(!tofinalize(o) && testbit(o->gch.marked, LOCALMARK));
+    lua_assert(testbit(o->gch.marked, NOLOCALBIT));
+    lua_assert(gch(o)->tt == LUA_TTHREAD);
+  }
   /* check 'localfin' list */
   checkgray(g, g->localfin);
   for (o = g->localfin; o != NULL; o = gch(o)->next) {
@@ -650,8 +655,8 @@ static int gc_local (lua_State *L) {
 
 static int gc_state (lua_State *L) {
   static const char *statenames[] = {"propagate", "atomic",
-    "sweeplocal", "sweeplocfin", "sweepfin", "sweepall", "sweeptobefnz",
-    "sweepmainth", "pause", ""};
+    "sweeplocal", "sweeplocfin", "sweepfin", "sweepall",
+    "sweeptobefnz", "sweepthreads", "sweepend", "pause", ""};
   int option = luaL_checkoption(L, 1, "", statenames);
   if (option == GCSpause + 1) {
     lua_pushstring(L, statenames[G(L)->gcstate]);