diff --git a/bugs b/bugs index 14d143bb..d1f429a6 100644 --- a/bugs +++ b/bugs @@ -1880,8 +1880,8 @@ patch = [[ +++ lundump.c 2008/04/04 19:51:41 2.7.1.4 @@ -1,5 +1,5 @@ /* --** $Id: bugs,v 1.125 2013/07/05 18:02:28 roberto Exp roberto $ -+** $Id: bugs,v 1.125 2013/07/05 18:02:28 roberto Exp roberto $ +-** $Id: bugs,v 1.126 2013/08/30 15:51:12 roberto Exp roberto $ ++** $Id: bugs,v 1.126 2013/08/30 15:51:12 roberto Exp roberto $ ** load precompiled Lua chunks ** See Copyright Notice in lua.h */ @@ -3133,7 +3133,20 @@ patch = [[ return ts; ]] } -]=] +] + + +Bug{ +what = [[Call to macro 'luai_userstateclose' should be done only +after the calls to __gc methods.]], +report = [[Jean-Luc Jumpertz, 2013/09/02]], +since = [[ ]], +fix = nil, +example = [[No example]], +patch = [[ +]] +} +]=]=] --[=[ diff --git a/lgc.c b/lgc.c index aaa57a07..da1d3fdc 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.156 2013/08/29 13:34:16 roberto Exp roberto $ +** $Id: lgc.c,v 2.157 2013/08/30 19:14:26 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -777,8 +777,16 @@ static GCObject *udata2finalize (global_State *g) { GCObject *o = g->tobefnz; /* get first element */ lua_assert(tofinalize(o)); g->tobefnz = gch(o)->next; /* remove it from 'tobefnz' list */ - gch(o)->next = g->allgc; /* return it to 'allgc' list */ - g->allgc = o; + if (islocal(o)) { + lua_assert(!testbit(gch(o)->marked, LOCALMARK)); + gch(o)->next = g->localgc; /* return it to 'localgc' list */ + g->localgc = o; + } + else { /* return it to 'allgc' list */ + gch(o)->next = g->allgc; + g->allgc = o; + l_setbit(gch(o)->marked, LOCALMARK); + } resetbit(gch(o)->marked, FINALIZEDBIT); /* object is back in 'allgc' */ if (!keepinvariant(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ @@ -825,23 +833,38 @@ static void GCTM (lua_State *L, int propagateerrors) { /* -** move all unreachable objects (or 'all' objects) that need -** finalization from list 'finobj' to list 'tobefnz' (to be finalized) +** call all pending finalizers */ -static void separatetobefnz (lua_State *L, int all) { +static void callallpendingfinalizers (lua_State *L, int propagateerrors) { global_State *g = G(L); - GCObject **p = &g->finobj; + while (g->tobefnz) + GCTM(L, propagateerrors); +} + + +/* +** find last 'next' field in list 'p' list (to add elements in its end) +*/ +static GCObject **findlast (GCObject **p) { + while (*p != NULL) + p = &gch(*p)->next; + return p; +} + + +/* +** move all unreachable objects (or 'all' objects) that need +** finalization from list 'p' to list 'tobefnz' (to be finalized) +*/ +static void separatetobefnz_aux (global_State *g, GCObject **p, int all) { GCObject *curr; - GCObject **lastnext = &g->tobefnz; - /* find last 'next' field in 'tobefnz' list (to add elements in its end) */ - while (*lastnext != NULL) - lastnext = &gch(*lastnext)->next; + GCObject **lastnext = findlast(&g->tobefnz); while ((curr = *p) != NULL) { /* traverse all finalizable objects */ lua_assert(tofinalize(curr)); if (!(iswhite(curr) || all)) /* not being collected? */ p = &gch(curr)->next; /* don't bother with it */ else { - *p = gch(curr)->next; /* remove 'curr' from 'finobj' list */ + *p = gch(curr)->next; /* remove 'curr' from "fin" list */ gch(curr)->next = *lastnext; /* link at the end of 'tobefnz' list */ *lastnext = curr; lastnext = &gch(curr)->next; @@ -850,9 +873,15 @@ static void separatetobefnz (lua_State *L, int all) { } +static void separatetobefnz (global_State *g, int all) { + separatetobefnz_aux(g, &g->localfin, all); + separatetobefnz_aux(g, &g->finobj, all); +} + + /* ** if object 'o' has a finalizer, remove it from 'allgc' list (must -** search the list to find it) and link it in 'finobj' list. +** search the list to find it) and link it in 'localfin' or 'finobj' list. */ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { global_State *g = G(L); @@ -869,11 +898,11 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { /* search for pointer pointing to 'o' */ p = (testbit(ho->marked, LOCALMARK)) ? &g->allgc : &g->localgc; for (; *p != o; p = &gch(*p)->next) { /* empty */ } - *p = ho->next; /* remove 'o' from 'allgc' list */ - ho->next = g->finobj; /* link it in list 'finobj' */ - g->finobj = o; + *p = ho->next; /* remove 'o' from its list */ + p = (testbit(ho->marked, LOCALMARK)) ? &g->finobj : &g->localfin; + ho->next = *p; /* link it in a "fin" list */ + *p = o; l_setbit(ho->marked, FINALIZEDBIT); /* mark it as such */ - l_setbit(ho->marked, LOCALMARK); /* not in 'localgc' anymore */ if (!keepinvariant(g)) /* not keeping invariant? */ makewhite(g, o); /* "sweep" object */ } @@ -918,7 +947,8 @@ static void localmark (global_State *g) { } -static void localsweep (lua_State *L, global_State *g, GCObject **p) { +static void localsweep (lua_State *L, global_State *g) { + GCObject **p = &g->localgc; while (*p != NULL) { GCObject *curr = *p; if (!islocal(curr)) { /* is 'curr' no more local? */ @@ -946,11 +976,41 @@ static void localsweep (lua_State *L, global_State *g, GCObject **p) { } +static void separatelocal (global_State *g, int all) { + GCObject **p = &g->localfin; + GCObject **lastnext = findlast(&g->tobefnz); + while (*p != NULL) { + GCObject *curr = *p; + if (!islocal(curr)) { /* is 'curr' no more local? */ + *p = curr->gch.next; /* remove 'curr' from list */ + curr->gch.next = g->finobj; /* link 'curr' in 'finobj' list */ + g->finobj = curr; + /* mark it as out of local list */ + l_setbit(curr->gch.marked, LOCALMARK); + } + else { /* still local */ + if (testbit(curr->gch.marked, LOCALMARK) && !all) { /* locally alive? */ + resetbit(curr->gch.marked, LOCALMARK); + p = &curr->gch.next; /* go to next element */ + } + else { /* object is "dead" */ + *p = curr->gch.next; /* remove 'curr' from list */ + curr->gch.next = *lastnext; /* link at the end of 'tobefnz' list */ + *lastnext = curr; + lastnext = &curr->gch.next; + } + } + } +} + + static void luaC_localcollection (lua_State *L) { global_State *g = G(L); lua_assert(g->gcstate == GCSpause); localmark(g); - localsweep(L, g, &g->localgc); + localsweep(L, g); + separatelocal(g, 0); + callallpendingfinalizers(L, 1); } /* }====================================================== */ @@ -997,24 +1057,15 @@ static int entersweep (lua_State *L) { } -/* -** call all pending finalizers -*/ -static void callallpendingfinalizers (lua_State *L, int propagateerrors) { - global_State *g = G(L); - while (g->tobefnz) - GCTM(L, propagateerrors); -} - - void luaC_freeallobjects (lua_State *L) { global_State *g = G(L); - separatetobefnz(L, 1); /* separate all objects with finalizers */ - lua_assert(g->finobj == NULL); + separatetobefnz(g, 1); /* separate all objects with finalizers */ + lua_assert(g->finobj == NULL && g->localfin == NULL); callallpendingfinalizers(L, 0); g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; - sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ + 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->fixedgc); /* collect fixed objects */ @@ -1045,7 +1096,7 @@ static l_mem atomic (lua_State *L) { clearvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; work += g->GCmemtrav; /* stop counting (objects being finalized) */ - separatetobefnz(L, 0); /* separate objects to be finalized */ + separatetobefnz(g, 0); /* separate objects to be finalized */ markbeingfnz(g); /* mark objects that will be finalized */ propagateall(g); /* remark, to propagate `preserveness' */ work -= g->GCmemtrav; /* restart counting */ @@ -1106,6 +1157,9 @@ static lu_mem singlestep (lua_State *L) { return work + sw * GCSWEEPCOST; } case GCSsweeplocal: { + return sweepstep(L, g, GCSsweeplocfin, &g->localfin); + } + case GCSsweeplocfin: { return sweepstep(L, g, GCSsweepfin, &g->finobj); } case GCSsweepfin: { diff --git a/lgc.h b/lgc.h index db309360..7e385136 100644 --- a/lgc.h +++ b/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.69 2013/08/29 13:49:57 roberto Exp roberto $ +** $Id: lgc.h,v 2.70 2013/08/30 19:14:26 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -39,10 +39,11 @@ #define GCSpropagate 0 #define GCSatomic 1 #define GCSsweeplocal 2 -#define GCSsweepfin 3 -#define GCSsweepall 4 -#define GCSsweepmainth 5 -#define GCSpause 6 +#define GCSsweeplocfin 3 +#define GCSsweepfin 4 +#define GCSsweepall 5 +#define GCSsweepmainth 6 +#define GCSpause 7 #define issweepphase(g) \ diff --git a/lstate.c b/lstate.c index 842f6a42..e81d968d 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.108 2013/08/28 18:30:26 roberto Exp roberto $ +** $Id: lstate.c,v 2.109 2013/08/30 19:14:26 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -296,9 +296,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->panic = NULL; g->version = lua_version(NULL); g->gcstate = GCSpause; - g->allgc = NULL; - g->localgc = NULL; - g->finobj = NULL; + g->localgc = g->localfin = g->allgc = g->finobj = NULL; g->tobefnz = NULL; g->fixedgc = NULL; g->sweepgc = NULL; diff --git a/lstate.h b/lstate.h index e03b75f2..38bbb982 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.91 2013/08/27 18:53:35 roberto Exp roberto $ +** $Id: lstate.h,v 2.92 2013/08/30 19:14:26 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -121,8 +121,9 @@ typedef struct global_State { lu_byte gcrunning; /* true if GC is running */ GCObject *allgc; /* list of all collectable objects */ GCObject *localgc; /* list of local objects */ - GCObject *finobj; /* list of collectable objects with finalizers */ + GCObject *localfin; /* list of local objects with finalizers */ GCObject **sweepgc; /* current position of sweep in list */ + GCObject *finobj; /* list of collectable objects with finalizers */ GCObject *gray; /* list of gray objects */ GCObject *grayagain; /* list of objects to be traversed atomically */ GCObject *weak; /* list of tables with weak values */ diff --git a/ltests.c b/ltests.c index ec7631e7..a8890328 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 2.151 2013/08/27 20:04:00 roberto Exp roberto $ +** $Id: ltests.c,v 2.152 2013/08/30 19:14:26 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -202,17 +202,8 @@ static int testobjref2 (GCObject *f, GCObject *t) { static void printobj (global_State *g, GCObject *o) { - int i = 1; - GCObject *p; - for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++; - if (p == NULL) { - i = 1; - for (p = g->finobj; p != o && p != NULL; p = gch(p)->next) i++; - if (p == NULL) i = 0; /* zero means 'not found' */ - else i = -i; /* negative means 'found in findobj list */ - } - printf("||%d:%s(%p)-%s-%c(%02X)||", - i, ttypename(novariant(gch(o)->tt)), (void *)o, + printf("||%s(%p)-%s-%c(%02X)||", + ttypename(novariant(gch(o)->tt)), (void *)o, islocal(o)?"L":"NL", isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->marked); } @@ -344,9 +335,10 @@ static void checkstack (global_State *g, lua_State *L1) { static void checkobject (global_State *g, GCObject *o, int maybedead) { if (isdead(g, o)) - lua_assert(maybedead); + lua_assert(maybedead && issweepphase(g)); else { lua_assert(g->gcstate != GCSpause || iswhite(o)); + lua_assert(!islocal(o) || !testbit(gch(o)->marked, LOCALMARK)); switch (gch(o)->tt) { case LUA_TUSERDATA: { Table *mt = gco2u(o)->metatable; @@ -384,18 +376,18 @@ static void checkobject (global_State *g, GCObject *o, int maybedead) { #define TESTGRAYBIT 7 -static void checkgraylist (global_State *g, GCObject *l) { - UNUSED(g); /* better to keep it available if we need to print an object */ - while (l) { - lua_assert(isgray(l)); - lua_assert(!testbit(l->gch.marked, TESTGRAYBIT)); - l_setbit(l->gch.marked, TESTGRAYBIT); - switch (gch(l)->tt) { - case LUA_TTABLE: l = gco2t(l)->gclist; break; - case LUA_TLCL: l = gco2lcl(l)->gclist; break; - case LUA_TCCL: l = gco2ccl(l)->gclist; break; - case LUA_TTHREAD: l = gco2th(l)->gclist; break; - case LUA_TPROTO: l = gco2p(l)->gclist; break; +static void checkgraylist (global_State *g, GCObject *o) { + ((void)g); /* better to keep it available if we need to print an object */ + while (o) { + lua_assert(isgray(o)); + lua_assert(!testbit(o->gch.marked, TESTGRAYBIT)); + l_setbit(o->gch.marked, TESTGRAYBIT); + switch (gch(o)->tt) { + case LUA_TTABLE: o = gco2t(o)->gclist; break; + case LUA_TLCL: o = gco2lcl(o)->gclist; break; + case LUA_TCCL: o = gco2ccl(o)->gclist; break; + case LUA_TTHREAD: o = gco2th(o)->gclist; break; + case LUA_TPROTO: o = gco2p(o)->gclist; break; default: lua_assert(0); /* other objects cannot be gray */ } } @@ -451,30 +443,35 @@ int lua_checkmemory (lua_State *L) { 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)); - lua_assert(testbit(o->gch.marked, LOCALMARK)); + lua_assert(!tofinalize(o) && testbit(o->gch.marked, LOCALMARK)); } /* check 'finobj' list */ checkgray(g, g->finobj); for (o = g->finobj; o != NULL; o = gch(o)->next) { - lua_assert(tofinalize(o)); + checkobject(g, o, 0); + lua_assert(tofinalize(o) && testbit(o->gch.marked, LOCALMARK)); lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); - checkobject(g, o, 0); } /* check 'tobefnz' list */ checkgray(g, g->tobefnz); for (o = g->tobefnz; o != NULL; o = gch(o)->next) { lua_assert(!iswhite(o) || g->gcstate == GCSpause); lua_assert(!isdead(g, o) && tofinalize(o)); - lua_assert(gch(o)->tt == LUA_TUSERDATA || - gch(o)->tt == LUA_TTABLE); + lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); } /* check 'localgc' list */ checkgray(g, g->localgc); for (o = g->localgc; o != NULL; o = gch(o)->next) { checkobject(g, o, 1); - lua_assert(!testbit(o->gch.marked, LOCALMARK)); + lua_assert(!tofinalize(o) && !testbit(o->gch.marked, LOCALMARK)); + } + /* check 'localfin' list */ + checkgray(g, g->localfin); + for (o = g->localfin; o != NULL; o = gch(o)->next) { + checkobject(g, o, 0); + lua_assert(tofinalize(o) && !testbit(o->gch.marked, LOCALMARK)); + lua_assert(gch(o)->tt == LUA_TUSERDATA || gch(o)->tt == LUA_TTABLE); } return 0; } @@ -653,7 +650,7 @@ static int gc_local (lua_State *L) { static int gc_state (lua_State *L) { static const char *statenames[] = {"propagate", "atomic", - "sweeplocal", "sweepfin", "sweepall", "sweepmainth", + "sweeplocal", "sweeplocfin", "sweepfin", "sweepall", "sweepmainth", "pause", ""}; int option = luaL_checkoption(L, 1, "", statenames); if (option == GCSpause + 1) {