mirror of https://github.com/rusefi/lua.git
local collection now calls finalizers
This commit is contained in:
parent
1bf4faec64
commit
aeff4f79fa
19
bugs
19
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 = [[
|
||||
]]
|
||||
}
|
||||
]=]=]
|
||||
|
||||
|
||||
--[=[
|
||||
|
|
120
lgc.c
120
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: {
|
||||
|
|
11
lgc.h
11
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) \
|
||||
|
|
6
lstate.c
6
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;
|
||||
|
|
5
lstate.h
5
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 */
|
||||
|
|
63
ltests.c
63
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) {
|
||||
|
|
Loading…
Reference in New Issue