From 6fda6a530265268c01a83c31f8fc30e34753bbf1 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 22 Jan 2001 16:01:38 -0200 Subject: [PATCH] support for multiple stacks sharing the same global environment --- lgc.c | 74 +++++++++++++++++++++---------------- lstate.c | 111 ++++++++++++++++++++++++++++++++++--------------------- lstate.h | 8 ++-- ltests.c | 16 +++++++- lua.c | 4 +- lua.h | 4 +- 6 files changed, 134 insertions(+), 83 deletions(-) diff --git a/lgc.c b/lgc.c index abe78425..db713767 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.76 2001/01/18 15:59:09 roberto Exp roberto $ +** $Id: lgc.c,v 1.77 2001/01/19 13:20:30 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -47,22 +47,6 @@ static void protomark (Proto *f) { } -static void markstack (lua_State *L, GCState *st) { - StkId o; - for (o=L->stack; otop; o++) - markobject(st, o); -} - - -static void marklock (global_State *G, GCState *st) { - int i; - for (i=0; inref; i++) { - if (G->refArray[i].st == LOCK) - markobject(st, &G->refArray[i].o); - } -} - - static void markclosure (GCState *st, Closure *cl) { if (!ismarked(cl)) { if (!cl->isC) @@ -73,14 +57,10 @@ static void markclosure (GCState *st, Closure *cl) { } -static void marktagmethods (global_State *G, GCState *st) { - int e; - for (e=0; entag; t++) { - Closure *cl = luaT_gettm(G, t, e); - if (cl) markclosure(st, cl); - } +static void marktable (GCState *st, Hash *h) { + if (!ismarked(h)) { + h->mark = st->tmark; /* chain it in list of marked */ + st->tmark = h; } } @@ -97,10 +77,7 @@ static void markobject (GCState *st, TObject *o) { markclosure(st, clvalue(o)); break; case LUA_TTABLE: { - if (!ismarked(hvalue(o))) { - hvalue(o)->mark = st->tmark; /* chain it in list of marked */ - st->tmark = hvalue(o); - } + marktable(st, hvalue(o)); break; } default: break; /* numbers, etc */ @@ -108,13 +85,46 @@ static void markobject (GCState *st, TObject *o) { } +static void markstacks (lua_State *L, GCState *st) { + lua_State *L1 = L; + do { /* for each thread */ + StkId o; + marktable(st, L1->gt); /* mark table of globals */ + for (o=L1->stack; otop; o++) + markobject(st, o); + lua_assert(L->previous->next == L && L->next->previous == L); + L1 = L1->next; + } while (L1 != L); +} + + +static void marklock (global_State *G, GCState *st) { + int i; + for (i=0; inref; i++) { + if (G->refArray[i].st == LOCK) + markobject(st, &G->refArray[i].o); + } +} + + +static void marktagmethods (global_State *G, GCState *st) { + int e; + for (e=0; entag; t++) { + Closure *cl = luaT_gettm(G, t, e); + if (cl) markclosure(st, cl); + } + } +} + + static void markall (lua_State *L) { GCState st; st.cmark = NULL; - st.tmark = L->gt; /* put table of globals in mark list */ - L->gt->mark = NULL; + st.tmark = NULL; marktagmethods(G(L), &st); /* mark tag methods */ - markstack(L, &st); /* mark stack objects */ + markstacks(L, &st); /* mark all stacks */ marklock(G(L), &st); /* mark locked objects */ for (;;) { /* mark tables and closures */ if (st.cmark) { diff --git a/lstate.c b/lstate.c index 67613b3d..5783f639 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.50 2000/12/28 12:55:41 roberto Exp roberto $ +** $Id: lstate.c,v 1.51 2001/01/19 13:20:30 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -38,52 +38,70 @@ static int errormessage (lua_State *L) { } +struct Sopen { + int stacksize; + lua_State *L; +}; + + /* ** open parts that may cause memory-allocation errors */ static void f_luaopen (lua_State *L, void *ud) { - int stacksize = *(int *)ud; - if (stacksize == 0) - stacksize = DEFAULT_STACK_SIZE; + struct Sopen *so = (struct Sopen *)ud; + if (so->stacksize == 0) + so->stacksize = DEFAULT_STACK_SIZE; else - stacksize += LUA_MINSTACK; - L->G = luaM_new(L, global_State); - G(L)->strt.size = G(L)->udt.size = 0; - G(L)->strt.nuse = G(L)->udt.nuse = 0; - G(L)->strt.hash = G(L)->udt.hash = NULL; - G(L)->Mbuffer = NULL; - G(L)->Mbuffsize = 0; - G(L)->rootproto = NULL; - G(L)->rootcl = NULL; - G(L)->roottable = NULL; - G(L)->TMtable = NULL; - G(L)->sizeTM = 0; - G(L)->ntag = 0; - G(L)->refArray = NULL; - G(L)->nref = 0; - G(L)->sizeref = 0; - G(L)->refFree = NONEXT; - G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); - G(L)->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */ - L->gt = luaH_new(L, 10); /* table of globals */ - luaD_init(L, stacksize); - luaS_init(L); - luaX_init(L); - luaT_init(L); - lua_newtable(L); - lua_ref(L, 1); /* create registry */ - lua_register(L, LUA_ERRORMESSAGE, errormessage); + so->stacksize += LUA_MINSTACK; + if (so->L != NULL) { /* shared global state? */ + L->G = G(so->L); + L->gt = so->L->gt; /* share table of globals */ + so->L->next->previous = L; /* insert L into linked list */ + L->next = so->L->next; + so->L->next = L; + L->previous = so->L; + luaD_init(L, so->stacksize); /* init stack */ + } + else { /* create a new global state */ + L->G = luaM_new(L, global_State); + G(L)->strt.size = G(L)->udt.size = 0; + G(L)->strt.nuse = G(L)->udt.nuse = 0; + G(L)->strt.hash = G(L)->udt.hash = NULL; + G(L)->Mbuffer = NULL; + G(L)->Mbuffsize = 0; + G(L)->rootproto = NULL; + G(L)->rootcl = NULL; + G(L)->roottable = NULL; + G(L)->TMtable = NULL; + G(L)->sizeTM = 0; + G(L)->ntag = 0; + G(L)->refArray = NULL; + G(L)->nref = 0; + G(L)->sizeref = 0; + G(L)->refFree = NONEXT; + G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); + G(L)->GCthreshold = MAX_INT; /* to avoid GC during pre-definitions */ + luaD_init(L, so->stacksize); /* init stack */ + L->gt = luaH_new(L, 10); /* table of globals */ + luaS_init(L); + luaX_init(L); + luaT_init(L); + lua_newtable(L); + lua_ref(L, 1); /* create registry */ + lua_register(L, LUA_ERRORMESSAGE, errormessage); #ifdef LUA_DEBUG - luaB_opentests(L); - if (lua_state == NULL) lua_state = L; /* keep first state to be opened */ - lua_assert(lua_gettop(L) == 0); + luaB_opentests(L); + if (lua_state == NULL) lua_state = L; /* keep first state to be opened */ + lua_assert(lua_gettop(L) == 0); #endif + G(L)->GCthreshold = 2*G(L)->nblocks; + } } -LUA_API lua_State *lua_open (int stacksize) { - lua_State *L; - L = luaM_new(NULL, lua_State); +LUA_API lua_State *lua_open (lua_State *OL, int stacksize) { + struct Sopen so; + lua_State *L = luaM_new(OL, lua_State); if (L == NULL) return NULL; /* memory allocation error */ L->G = NULL; L->stack = NULL; @@ -92,19 +110,28 @@ LUA_API lua_State *lua_open (int stacksize) { L->callhook = NULL; L->linehook = NULL; L->allowhooks = 1; - if (luaD_runprotected(L, f_luaopen, &stacksize) != 0) { + L->next = L->previous = L; + so.stacksize = stacksize; + so.L = OL; + if (luaD_runprotected(L, f_luaopen, &so) != 0) { /* memory allocation error: free partial state */ lua_close(L); return NULL; } - G(L)->GCthreshold = 2*G(L)->nblocks; return L; } LUA_API void lua_close (lua_State *L) { + lua_State *L1 = L->next; /* any surviving thread (if there is one) */ lua_assert(L != lua_state || lua_gettop(L) == 0); - if (G(L)) { /* close global state */ + if (L1 == L) L1 = NULL; /* no surviving threads */ + if (L1 != NULL) { /* are there other threads? */ + lua_assert(L->previous != L); + L->previous->next = L->next; + L->next->previous = L->previous; + } + else if (G(L)) { /* last thread; close global state */ luaC_collect(L, 1); /* collect all elements */ lua_assert(G(L)->rootproto == NULL); lua_assert(G(L)->rootcl == NULL); @@ -115,8 +142,8 @@ LUA_API void lua_close (lua_State *L) { luaM_freearray(L, G(L)->Mbuffer, G(L)->Mbuffsize, char); luaM_freelem(NULL, L->G, global_State); } - luaM_freearray(NULL, L->stack, L->stacksize, TObject); - luaM_freelem(NULL, L, lua_State); + luaM_freearray(L1, L->stack, L->stacksize, TObject); + luaM_freelem(L1, L, lua_State); lua_assert(L != lua_state || memdebug_numblocks == 0); lua_assert(L != lua_state || memdebug_total == 0); } diff --git a/lstate.h b/lstate.h index c7735b04..84fadd2f 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.43 2000/12/26 18:46:09 roberto Exp roberto $ +** $Id: lstate.h,v 1.44 2001/01/19 13:20:30 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -74,12 +74,14 @@ struct lua_State { StkId stack_last; /* last free slot in the stack */ int stacksize; StkId Cbase; /* base for current C function */ - struct lua_longjmp *errorJmp; /* current error recover point */ Hash *gt; /* table for globals */ + global_State *G; lua_Hook callhook; lua_Hook linehook; int allowhooks; - global_State *G; + struct lua_longjmp *errorJmp; /* current error recover point */ + lua_State *next; /* circular double linked list of states */ + lua_State *previous; }; diff --git a/ltests.c b/ltests.c index dbfdd7ca..ff841472 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 1.57 2001/01/18 15:59:09 roberto Exp roberto $ +** $Id: ltests.c,v 1.58 2001/01/19 13:20:30 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -270,8 +270,19 @@ static int udataval (lua_State *L) { return 1; } + +static int doonnewstack (lua_State *L) { + lua_State *L1 = lua_open(L, luaL_check_int(L, 1)); + if (L1 == NULL) return 0; + lua_dostring(L1, luaL_check_string(L, 2)); + lua_pushnumber(L, 1); + lua_close(L1); + return 1; +} + + static int newstate (lua_State *L) { - lua_State *L1 = lua_open(luaL_check_int(L, 1)); + lua_State *L1 = lua_open(NULL, luaL_check_int(L, 1)); if (L1) lua_pushuserdata(L, L1); else @@ -518,6 +529,7 @@ static const struct luaL_reg tests_funcs[] = { {"unref", unref}, {"newuserdata", newuserdata}, {"udataval", udataval}, + {"doonnewstack", doonnewstack}, {"newstate", newstate}, {"closestate", closestate}, {"doremote", doremote}, diff --git a/lua.c b/lua.c index 5b8732a4..d8eca6a8 100644 --- a/lua.c +++ b/lua.c @@ -1,5 +1,5 @@ /* -** $Id: lua.c,v 1.55 2000/10/20 16:36:32 roberto Exp roberto $ +** $Id: lua.c,v 1.56 2001/01/10 16:58:11 roberto Exp roberto $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ @@ -311,7 +311,7 @@ int main (int argc, char *argv[]) { int status; opt.toclose = 0; getstacksize(argc, argv, &opt); /* handle option `-s' */ - L = lua_open(opt.stacksize); /* create state */ + L = lua_open(NULL, opt.stacksize); /* create state */ userinit(); /* open libraries */ register_getargs(argv); /* create `getargs' function */ status = handle_argv(argv+1, &opt); diff --git a/lua.h b/lua.h index 9279aa2e..c8a105da 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.81 2000/12/22 16:58:41 roberto Exp roberto $ +** $Id: lua.h,v 1.82 2001/01/10 16:58:11 roberto Exp roberto $ ** Lua - An Extensible Extension Language ** TeCGraf: Grupo de Tecnologia em Computacao Grafica, PUC-Rio, Brazil ** e-mail: lua@tecgraf.puc-rio.br @@ -81,7 +81,7 @@ typedef int (*lua_CFunction) (lua_State *L); /* ** state manipulation */ -LUA_API lua_State *lua_open (int stacksize); +LUA_API lua_State *lua_open (lua_State *L, int stacksize); LUA_API void lua_close (lua_State *L);