Browse Source

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

pull/9/head
Roberto Ierusalimschy 11 years ago
parent
commit
dd373a8f66
  1. 21
      lgc.c
  2. 9
      lgc.h
  3. 20
      lstate.c
  4. 23
      lstate.h
  5. 19
      ltests.c

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

9
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 ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -43,12 +43,13 @@
#define GCSsweepfin 4 #define GCSsweepfin 4
#define GCSsweepall 5 #define GCSsweepall 5
#define GCSsweeptobefnz 6 #define GCSsweeptobefnz 6
#define GCSsweepmainth 7 #define GCSsweepthreads 7
#define GCSpause 8 #define GCSsweepend 8
#define GCSpause 9
#define issweepphase(g) \ #define issweepphase(g) \
(GCSsweeplocal <= (g)->gcstate && (g)->gcstate <= GCSsweepmainth) (GCSsweeplocal <= (g)->gcstate && (g)->gcstate <= GCSsweepend)
/* /*

20
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 ** Global State
** See Copyright Notice in lua.h ** 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); sethvalue(L, &g->l_registry, registry);
luaH_resize(L, registry, LUA_RIDX_LAST, 0); luaH_resize(L, registry, LUA_RIDX_LAST, 0);
nolocal(obj2gco(registry)); 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 */ /* registry[LUA_RIDX_MAINTHREAD] = L */
setthvalue(L, &temp, L); /* temp = L */ setthvalue(L, &temp, L); /* temp = L */
luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp);
@ -243,11 +235,11 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
luaC_checkGC(L); luaC_checkGC(L);
/* create new thread */ /* create new thread */
L1 = &cast(LX *, luaM_newobject(L, LUA_TTHREAD, sizeof(LX)))->l; 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; L1->tt = LUA_TTHREAD;
/* link it after 'l_registry' */ /* link it on list of threads */
L1->next = hvalue(&g->l_registry)->next; L1->next = g->mainthread->next;
hvalue(&g->l_registry)->next = obj2gco(L1); g->mainthread->next = obj2gco(L1);
setthvalue(L, L->top, L1); setthvalue(L, L->top, L1);
api_incr_top(L); api_incr_top(L);
preinit_state(L1, g); preinit_state(L1, g);
@ -283,7 +275,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
L->next = NULL; L->next = NULL;
L->tt = LUA_TTHREAD; L->tt = LUA_TTHREAD;
g->currentwhite = bitmask(WHITE0BIT); g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g) | bitmask(NOLOCALBIT); L->marked = luaC_white(g) | bit2mask(NOLOCALBIT, LOCALMARK);
g->gckind = KGC_NORMAL; g->gckind = KGC_NORMAL;
preinit_state(L, g); preinit_state(L, g);
g->frealloc = f; g->frealloc = f;

23
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 ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -17,19 +17,18 @@
/* /*
** Some notes about garbage-collected objects: All objects in Lua must ** Some notes about garbage-collected objects: All objects in Lua must
** be kept somehow accessible until being freed. ** 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 ** mainthread->next: all threads;
** 'next' of the CommonHeader. Threads (except the main one) ar kept ** localgc: all local objects not marked for finalization;
** at the end of the 'allgc' list, after the 'l_registry' (which is ** localfin: all local objects marked for finalization;
** the first object to be added to the list). ** allgc: all non local objects not marked for finalization;
** ** finobj: all non local objects marked for finalization;
** List 'fixedgc' keep objects that are not to be collected (currently ** tobefnz: all objects ready to be finalized;
** fixedgc: all objects that are not to be collected (currently
** only small strings, such as reserved words). ** 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.
*/ */

19
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 ** Internal Module for Debugging of the Lua Implementation
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -423,7 +423,6 @@ int lua_checkmemory (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o; GCObject *o;
int maybedead; int maybedead;
int isthread;
if (keepinvariant(g)) { if (keepinvariant(g)) {
lua_assert(!iswhite(obj2gco(g->mainthread))); lua_assert(!iswhite(obj2gco(g->mainthread)));
lua_assert(!iswhite(gcvalue(&g->l_registry))); lua_assert(!iswhite(gcvalue(&g->l_registry)));
@ -443,14 +442,20 @@ int lua_checkmemory (lua_State *L) {
/* check 'allgc' list */ /* check 'allgc' list */
checkgray(g, g->allgc); checkgray(g, g->allgc);
maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSsweepall); maybedead = (GCSatomic < g->gcstate && g->gcstate <= GCSsweepall);
isthread = 0; /* not traversing threads (yet) */
for (o = g->allgc; o != NULL; o = gch(o)->next) { 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); checkobject(g, o, maybedead);
lua_assert(!tofinalize(o) && testbit(o->gch.marked, LOCALMARK)); lua_assert(!tofinalize(o) && testbit(o->gch.marked, LOCALMARK));
lua_assert(testbit(o->gch.marked, NOLOCALBIT)); 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 */ /* check 'localfin' list */
checkgray(g, g->localfin); checkgray(g, g->localfin);
for (o = g->localfin; o != NULL; o = gch(o)->next) { 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 int gc_state (lua_State *L) {
static const char *statenames[] = {"propagate", "atomic", static const char *statenames[] = {"propagate", "atomic",
"sweeplocal", "sweeplocfin", "sweepfin", "sweepall", "sweeptobefnz", "sweeplocal", "sweeplocfin", "sweepfin", "sweepall",
"sweepmainth", "pause", ""}; "sweeptobefnz", "sweepthreads", "sweepend", "pause", ""};
int option = luaL_checkoption(L, 1, "", statenames); int option = luaL_checkoption(L, 1, "", statenames);
if (option == GCSpause + 1) { if (option == GCSpause + 1) {
lua_pushstring(L, statenames[G(L)->gcstate]); lua_pushstring(L, statenames[G(L)->gcstate]);

Loading…
Cancel
Save