mirror of https://github.com/rusefi/lua.git
new list 'twups' to allow traversal of upvalues from dead threads
(+ fixed some problems with cycles involving those upvalues)
This commit is contained in:
parent
ffa96d988d
commit
d764cc5522
16
lfunc.c
16
lfunc.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lfunc.c,v 2.39 2014/02/13 12:11:34 roberto Exp roberto $
|
||||
** $Id: lfunc.c,v 2.40 2014/02/15 13:12:01 roberto Exp roberto $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -35,7 +35,9 @@ Closure *luaF_newLclosure (lua_State *L, int n) {
|
|||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** fill a closure with new closed upvalues
|
||||
*/
|
||||
void luaF_initupvals (lua_State *L, LClosure *cl) {
|
||||
int i;
|
||||
for (i = 0; i < cl->nupvalues; i++) {
|
||||
|
@ -52,18 +54,24 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
|
|||
UpVal **pp = &L->openupval;
|
||||
UpVal *p;
|
||||
UpVal *uv;
|
||||
lua_assert(isintwups(L) || L->openupval == NULL);
|
||||
while (*pp != NULL && (p = *pp)->v >= level) {
|
||||
lua_assert(upisopen(p));
|
||||
if (p->v == level) /* found a corresponding upvalue? */
|
||||
return p; /* return it */
|
||||
pp = &p->u.open.next;
|
||||
}
|
||||
/* not found: create a new one */
|
||||
/* not found: create a new upvalue */
|
||||
uv = luaM_new(L, UpVal);
|
||||
uv->refcount = 0;
|
||||
uv->u.open.next = *pp;
|
||||
uv->u.open.next = *pp; /* link it to list of open upvalues */
|
||||
uv->u.open.touched = 1;
|
||||
*pp = uv;
|
||||
uv->v = level; /* current value lives in the stack */
|
||||
if (!isintwups(L)) { /* thread not in list of threads with upvalues? */
|
||||
L->twups = G(L)->twups; /* link it to the list */
|
||||
G(L)->twups = L;
|
||||
}
|
||||
return uv;
|
||||
}
|
||||
|
||||
|
|
6
lfunc.h
6
lfunc.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lfunc.h,v 2.11 2013/09/11 15:17:00 roberto Exp roberto $
|
||||
** $Id: lfunc.h,v 2.12 2014/02/15 13:12:01 roberto Exp roberto $
|
||||
** Auxiliary functions to manipulate prototypes and closures
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -18,6 +18,10 @@
|
|||
cast(int, sizeof(TValue *)*((n)-1)))
|
||||
|
||||
|
||||
/* test whether thread is in 'twups' list */
|
||||
#define isintwups(L) (L->twups != L)
|
||||
|
||||
|
||||
/*
|
||||
** Upvalues for Lua closures
|
||||
*/
|
||||
|
|
45
lgc.c
45
lgc.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lgc.c,v 2.174 2014/02/14 16:43:14 roberto Exp roberto $
|
||||
** $Id: lgc.c,v 2.175 2014/02/15 13:12:01 roberto Exp roberto $
|
||||
** Garbage Collector
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -23,6 +23,11 @@
|
|||
#include "ltm.h"
|
||||
|
||||
|
||||
/*
|
||||
** internal state for collector while inside the atomic phase. The
|
||||
** collector should never be in this state while running regular code.
|
||||
*/
|
||||
#define GCSinsideatomic (GCSpause + 1)
|
||||
|
||||
/*
|
||||
** cost of sweeping one element (the size of a small object divided
|
||||
|
@ -288,15 +293,21 @@ static void markbeingfnz (global_State *g) {
|
|||
/*
|
||||
** Mark all values stored in marked open upvalues from non-marked threads.
|
||||
** (Values from marked threads were already marked when traversing the
|
||||
** thread.)
|
||||
** thread.) Remove from the list threads that no longer have upvalues and
|
||||
** not-marked threads.
|
||||
*/
|
||||
static void remarkupvals (global_State *g) {
|
||||
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? */
|
||||
UpVal *uv = gco2th(thread)->openupval;
|
||||
for (; uv != NULL; uv = uv->u.open.next) {
|
||||
lua_State *thread;
|
||||
lua_State **p = &g->twups;
|
||||
while ((thread = *p) != NULL) {
|
||||
lua_assert(!isblack(obj2gco(thread))); /* threads are never black */
|
||||
if (isgray(obj2gco(thread)) && thread->openupval != NULL)
|
||||
p = &thread->twups; /* keep marked thread with upvalues in the list */
|
||||
else { /* thread is not marked or without upvalues */
|
||||
UpVal *uv;
|
||||
*p = thread->twups; /* remove thread from the list */
|
||||
thread->twups = thread; /* mark that it is out of list */
|
||||
for (uv = thread->openupval; uv != NULL; uv = uv->u.open.next) {
|
||||
if (uv->u.open.touched) {
|
||||
markvalue(g, uv->v); /* remark upvalue's value */
|
||||
uv->u.open.touched = 0;
|
||||
|
@ -459,13 +470,19 @@ static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
|
|||
return sizeCclosure(cl->nupvalues);
|
||||
}
|
||||
|
||||
/*
|
||||
** open upvalues point to values in a thread, so those values should
|
||||
** be marked when the thread is traversed except in the atomic phase
|
||||
** (because then the value cannot be changed by the thread and the
|
||||
** thread may not be traversed again)
|
||||
*/
|
||||
static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
|
||||
int i;
|
||||
markobject(g, cl->p); /* mark its prototype */
|
||||
for (i = 0; i < cl->nupvalues; i++) { /* mark its upvalues */
|
||||
UpVal *uv = cl->upvals[i];
|
||||
if (uv != NULL) {
|
||||
if (upisopen(uv))
|
||||
if (upisopen(uv) && g->gcstate != GCSinsideatomic)
|
||||
uv->u.open.touched = 1; /* can be marked in 'remarkupvals' */
|
||||
else
|
||||
markvalue(g, uv->v);
|
||||
|
@ -480,12 +497,19 @@ static lu_mem traversestack (global_State *g, lua_State *th) {
|
|||
StkId o = th->stack;
|
||||
if (o == NULL)
|
||||
return 1; /* stack not completely built yet */
|
||||
lua_assert(g->gcstate == GCSinsideatomic ||
|
||||
th->openupval == NULL || isintwups(th));
|
||||
for (; o < th->top; o++) /* mark live elements in the stack */
|
||||
markvalue(g, o);
|
||||
if (g->gcstate == GCSatomic) { /* final traversal? */
|
||||
if (g->gcstate == GCSinsideatomic) { /* final traversal? */
|
||||
StkId lim = th->stack + th->stacksize; /* real end of stack */
|
||||
for (; o < lim; o++) /* clear not-marked stack slice */
|
||||
setnilvalue(o);
|
||||
/* 'remarkupvals' may have removed thread from 'twups' list */
|
||||
if (!isintwups(th) && th->openupval != NULL) {
|
||||
th->twups = g->twups; /* link it back to the list */
|
||||
g->twups = th;
|
||||
}
|
||||
}
|
||||
else {
|
||||
CallInfo *ci;
|
||||
|
@ -941,6 +965,7 @@ static l_mem atomic (lua_State *L) {
|
|||
l_mem work = -cast(l_mem, g->GCmemtrav); /* start counting work */
|
||||
GCObject *origweak, *origall;
|
||||
lua_assert(!iswhite(obj2gco(g->mainthread)));
|
||||
g->gcstate = GCSinsideatomic;
|
||||
markobject(g, L); /* mark running thread */
|
||||
/* registry and global metatables may be changed by API */
|
||||
markvalue(g, &g->l_registry);
|
||||
|
|
4
lstate.c
4
lstate.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lstate.c,v 2.118 2014/02/13 12:11:34 roberto Exp roberto $
|
||||
** $Id: lstate.c,v 2.119 2014/02/13 14:46:38 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -222,6 +222,7 @@ static void preinit_thread (lua_State *L, global_State *g) {
|
|||
L->stack = NULL;
|
||||
L->ci = NULL;
|
||||
L->stacksize = 0;
|
||||
L->twups = L; /* thread has no upvalues */
|
||||
L->errorJmp = NULL;
|
||||
L->nCcalls = 0;
|
||||
L->hook = NULL;
|
||||
|
@ -317,6 +318,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
|
|||
g->sweepgc = NULL;
|
||||
g->gray = g->grayagain = NULL;
|
||||
g->weak = g->ephemeron = g->allweak = NULL;
|
||||
g->twups = NULL;
|
||||
g->totalbytes = sizeof(LG);
|
||||
g->GCdebt = 0;
|
||||
g->gcfinnum = 0;
|
||||
|
|
4
lstate.h
4
lstate.h
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
** $Id: lstate.h,v 2.99 2014/02/13 12:11:34 roberto Exp roberto $
|
||||
** $Id: lstate.h,v 2.100 2014/02/13 14:46:38 roberto Exp roberto $
|
||||
** Global State
|
||||
** See Copyright Notice in lua.h
|
||||
*/
|
||||
|
@ -124,6 +124,7 @@ typedef struct global_State {
|
|||
GCObject *allweak; /* list of all-weak tables */
|
||||
GCObject *tobefnz; /* list of userdata to be GC */
|
||||
GCObject *fixedgc; /* list of objects not to be collected */
|
||||
struct lua_State *twups; /* list of threads with open upvalues */
|
||||
Mbuffer buff; /* temporary buffer for string concatenation */
|
||||
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
|
||||
int gcpause; /* size of pause between successive GCs */
|
||||
|
@ -159,6 +160,7 @@ struct lua_State {
|
|||
lua_Hook hook;
|
||||
UpVal *openupval; /* list of open upvalues in this stack */
|
||||
GCObject *gclist;
|
||||
struct lua_State *twups; /* list of threads with open upvalues */
|
||||
struct lua_longjmp *errorJmp; /* current error recover point */
|
||||
ptrdiff_t errfunc; /* current error handling function (stack index) */
|
||||
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
|
||||
|
|
Loading…
Reference in New Issue