From d56d4cf776b2a874e35d7a92c506840f4a2051b6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 11 Jan 2002 18:26:52 -0200 Subject: [PATCH] distinct functions to create/destroy states and threads --- ldo.h | 3 +- lgc.c | 6 ++ lstate.c | 203 ++++++++++++++++++++++++++++++++----------------------- lstate.h | 6 ++ ltests.c | 14 +++- ltests.h | 3 - lua.h | 6 +- 7 files changed, 144 insertions(+), 97 deletions(-) diff --git a/ldo.h b/ldo.h index 769fccb9..83ed513b 100644 --- a/ldo.h +++ b/ldo.h @@ -1,5 +1,5 @@ /* -** $Id: ldo.h,v 1.1 2001/11/29 22:14:34 rieru Exp rieru $ +** $Id: ldo.h,v 1.38 2002/01/11 20:24:39 roberto Exp $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -22,7 +22,6 @@ #define luaD_checkstack(L,n) if (L->stack_last-(n)<=L->top) luaD_stackerror(L) -void luaD_init (lua_State *L, int stacksize); void luaD_lineHook (lua_State *L, int line, lua_Hook linehook); void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event); StkId luaD_precall (lua_State *L, StkId func); diff --git a/lgc.c b/lgc.c index 64eee046..696c726c 100644 --- a/lgc.c +++ b/lgc.c @@ -126,6 +126,12 @@ static void markstacks (GCState *st) { lua_State *L1 = st->L; do { /* for each thread */ StkId o, lim; + if (L1->base_ci == NULL) { /* incomplete state? */ + lua_assert(L1 != st->L); + L1 = L1->next; + luaE_closethread(st->L, L1->previous); /* collect it */ + continue; + } for (o=L1->stack; otop; o++) markobject(st, o); lim = (L1->stack_last - L1->ci->base > MAXSTACK) ? L1->ci->base+MAXSTACK diff --git a/lstate.c b/lstate.c index bf669bec..ca606adb 100644 --- a/lstate.c +++ b/lstate.c @@ -26,7 +26,26 @@ struct Sopen { }; -static void close_state (lua_State *L, lua_State *OL); +static void close_state (lua_State *L); + + +static void stack_init (lua_State *L, lua_State *OL, int stacksize) { + if (stacksize == 0) + stacksize = DEFAULT_STACK_SIZE; + else + stacksize += LUA_MINSTACK; + stacksize += EXTRA_STACK; + L->stack = luaM_newvector(OL, stacksize, TObject); + L->stacksize = stacksize; + L->top = L->stack + RESERVED_STACK_PREFIX; + L->stack_last = L->stack+(L->stacksize-EXTRA_STACK)-1; + L->base_ci = luaM_newvector(OL, 10, CallInfo); + L->ci = L->base_ci; + L->ci->base = L->top; + L->ci->savedpc = NULL; + L->size_ci = 10; + L->end_ci = L->base_ci + L->size_ci; +} /* @@ -34,93 +53,102 @@ static void close_state (lua_State *L, lua_State *OL); */ static void f_luaopen (lua_State *L, void *ud) { struct Sopen *so = cast(struct Sopen *, ud); - if (so->stacksize == 0) - so->stacksize = DEFAULT_STACK_SIZE; - else - so->stacksize += LUA_MINSTACK; - if (so->L != NULL) { /* shared global state? */ - L->_G = G(so->L); - 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 */ - setobj(defaultet(L), defaultet(so->L)); /* share default event table */ - setobj(gt(L), gt(so->L)); /* share table of globals */ - setobj(registry(L), registry(so->L)); /* share registry */ - } - else { /* create a new global state */ - L->_G = luaM_new(L, global_State); - G(L)->strt.size = 0; - G(L)->strt.nuse = 0; - G(L)->strt.hash = NULL; - G(L)->Mbuffer = NULL; - G(L)->Mbuffsize = 0; - G(L)->rootproto = NULL; - G(L)->rootcl = NULL; - G(L)->roottable = NULL; - G(L)->rootupval = NULL; - G(L)->rootudata = NULL; - G(L)->tmudata = NULL; - G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); - luaD_init(L, so->stacksize); /* init stack */ - /* create default event table with a dummy table, and then close the loop */ - sethvalue(defaultet(L), NULL); - sethvalue(defaultet(L), luaH_new(L, 0, 4)); - hvalue(defaultet(L))->eventtable = hvalue(defaultet(L)); - sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ - sethvalue(registry(L), luaH_new(L, 0, 0)); /* registry */ - luaS_resize(L, 4); /* initial size of string table */ - luaT_init(L); - luaX_init(L); - G(L)->GCthreshold = 4*G(L)->nblocks; - } + /* create a new global state */ + L->_G = luaM_new(L, global_State); + G(L)->strt.size = 0; + G(L)->strt.nuse = 0; + G(L)->strt.hash = NULL; + G(L)->Mbuffer = NULL; + G(L)->Mbuffsize = 0; + G(L)->rootproto = NULL; + G(L)->rootcl = NULL; + G(L)->roottable = NULL; + G(L)->rootupval = NULL; + G(L)->rootudata = NULL; + G(L)->tmudata = NULL; + G(L)->nblocks = sizeof(lua_State) + sizeof(global_State); + stack_init(L, L, so->stacksize); /* init stack */ + /* create default event table with a dummy table, and then close the loop */ + sethvalue(defaultet(L), NULL); + sethvalue(defaultet(L), luaH_new(L, 0, 4)); + hvalue(defaultet(L))->eventtable = hvalue(defaultet(L)); + sethvalue(gt(L), luaH_new(L, 0, 4)); /* table of globals */ + sethvalue(registry(L), luaH_new(L, 0, 0)); /* registry */ + luaS_resize(L, 4); /* initial size of string table */ + luaT_init(L); + luaX_init(L); + G(L)->GCthreshold = 4*G(L)->nblocks; +} + + +static void preinit_state (lua_State *L) { + L->stack = NULL; + L->stacksize = 0; + L->errorJmp = NULL; + L->callhook = NULL; + L->linehook = NULL; + L->openupval = NULL; + L->size_ci = 0; + L->base_ci = NULL; + L->allowhooks = 1; } LUA_API lua_State *lua_newthread (lua_State *OL, int stacksize) { - struct Sopen so; lua_State *L; - if (OL) lua_lock(OL); + lua_lock(OL); L = luaM_new(OL, lua_State); - if (L) { /* allocation OK? */ - L->_G = NULL; - L->stack = NULL; - L->stacksize = 0; - L->errorJmp = NULL; - L->callhook = NULL; - L->linehook = NULL; - L->openupval = NULL; - L->size_ci = 0; - L->base_ci = NULL; - L->allowhooks = 1; - 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 */ - close_state(L, OL); - L = NULL; - } - } - if (OL) lua_unlock(OL); + preinit_state(L); + L->_G = OL->_G; + OL->next->previous = L; /* insert L into linked list */ + L->next = OL->next; + OL->next = L; + L->previous = OL; + stack_init(L, OL, stacksize); /* init stack */ + setobj(defaultet(L), defaultet(OL)); /* share default event table */ + setobj(gt(L), gt(OL)); /* share table of globals */ + setobj(registry(L), registry(OL)); /* share registry */ + lua_unlock(OL); lua_userstateopen(L); return L; } -static void close_state (lua_State *L, lua_State *OL) { +LUA_API lua_State *lua_open (int stacksize) { + struct Sopen so; + lua_State *L; + L = luaM_new(NULL, lua_State); + if (L) { /* allocation OK? */ + preinit_state(L); + L->_G = NULL; + L->next = L->previous = L; + so.stacksize = stacksize; + so.L = NULL; + if (luaD_runprotected(L, f_luaopen, &so) != 0) { + /* memory allocation error: free partial state */ + close_state(L); + L = NULL; + } + } + lua_userstateopen(L); + return L; +} + + +void luaE_closethread (lua_State *OL, lua_State *L) { luaF_close(L, L->stack); /* close all upvalues for this thread */ lua_assert(L->openupval == NULL); - if (OL != 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 */ - if (G(L)->rootudata) /* (avoid problems with incomplete states) */ - luaC_callallgcTM(L); /* call GC tag methods for all udata */ - lua_assert(G(L)->tmudata == NULL); + L->previous->next = L->next; + L->next->previous = L->previous; + luaM_freearray(OL, L->base_ci, L->size_ci, CallInfo); + luaM_freearray(OL, L->stack, L->stacksize, TObject); + luaM_freelem(OL, L); +} + + +static void close_state (lua_State *L) { + luaF_close(L, L->stack); /* close all upvalues for this thread */ + if (G(L)) { /* close global state */ luaC_collect(L, 1); /* collect all elements */ lua_assert(G(L)->rootproto == NULL); lua_assert(G(L)->rootudata == NULL); @@ -131,21 +159,24 @@ static void close_state (lua_State *L, lua_State *OL) { luaM_freearray(L, G(L)->Mbuffer, G(L)->Mbuffsize, char); luaM_freelem(NULL, L->_G); } - luaM_freearray(OL, L->base_ci, L->size_ci, CallInfo); - luaM_freearray(OL, L->stack, L->stacksize, TObject); - luaM_freelem(OL, L); + luaE_closethread(NULL, L); +} + + +LUA_API void lua_closethread (lua_State *L, lua_State *thread) { + if (L == thread) lua_error(L, "cannot close only thread of a state"); + lua_lock(L); + luaE_closethread(L, thread); + lua_unlock(L); } LUA_API void lua_close (lua_State *L) { - lua_State *OL; - lua_assert(L != lua_state || lua_gettop(L) == 0); lua_lock(L); - OL = L->next; /* any surviving thread (if there is one) */ - if (OL == L) OL = NULL; /* no surviving threads */ - close_state(L, OL); - if (OL) lua_unlock(OL); /* cannot unlock over a freed state */ - lua_assert(L != lua_state || memdebug_numblocks == 0); - lua_assert(L != lua_state || memdebug_total == 0); + luaC_callallgcTM(L); /* call GC tag methods for all udata */ + lua_assert(G(L)->tmudata == NULL); + while (L->next != L) /* then, close all other threads */ + luaE_closethread(L, L->next); + close_state(L); } diff --git a/lstate.h b/lstate.h index b7d69af6..978ffbc1 100644 --- a/lstate.h +++ b/lstate.h @@ -64,6 +64,9 @@ struct lua_longjmp; /* defined in ldo.c */ #define RESERVED_STACK_PREFIX 3 +/* space to handle stack overflow errors */ +#define EXTRA_STACK (2*LUA_MINSTACK) + typedef struct stringtable { @@ -90,6 +93,7 @@ typedef struct CallInfo { #define ci_func(ci) (clvalue((ci)->base - 1)) +#define yield_results refi /* reuse this field */ /* @@ -138,5 +142,7 @@ struct lua_State { #define G(L) (L->_G) +void luaE_closethread (lua_State *OL, lua_State *L); + #endif diff --git a/ltests.c b/ltests.c index 72a448bd..3e63d0d3 100644 --- a/ltests.c +++ b/ltests.c @@ -36,7 +36,7 @@ #ifdef LUA_DEBUG -lua_State *lua_state = NULL; +static lua_State *lua_state = NULL; int islocked = 0; @@ -374,10 +374,9 @@ static int udataval (lua_State *L) { static int doonnewstack (lua_State *L) { lua_State *L1 = lua_newthread(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); + lua_closethread(L, L1); return 1; } @@ -652,6 +651,14 @@ static const struct luaL_reg tests_funcs[] = { }; +static void fim (void) { + if (!islocked) + lua_close(lua_state); + lua_assert(memdebug_numblocks == 0); + lua_assert(memdebug_total == 0); +} + + void luaB_opentests (lua_State *L) { *cast(int **, L) = &islocked; /* init lock */ lua_state = L; /* keep first state to be opened */ @@ -663,6 +670,7 @@ void luaB_opentests (lua_State *L) { luaL_openl(L, tests_funcs); /* open functions inside new table */ lua_setglobals(L); /* restore old table of globals */ lua_setglobal(L, "T"); /* set new table as global T */ + atexit(fim); } #endif diff --git a/ltests.h b/ltests.h index 18b703a6..12fac8d3 100644 --- a/ltests.h +++ b/ltests.h @@ -48,9 +48,6 @@ extern int islocked; #define lua_unlock(L) lua_assert(--(**cast(int **, L)) == 0) -extern lua_State *lua_state; - - void luaB_opentests (lua_State *L); #define LUA_USERINIT(L) (luaB_opentests(L), openstdlibs(L)) diff --git a/lua.h b/lua.h index 0a2f5b10..89b5818d 100644 --- a/lua.h +++ b/lua.h @@ -94,8 +94,10 @@ typedef LUA_NUMBER lua_Number; /* ** state manipulation */ -LUA_API lua_State *lua_newthread (lua_State *L, int stacksize); +LUA_API lua_State *lua_open (int stacksize); LUA_API void lua_close (lua_State *L); +LUA_API lua_State *lua_newthread (lua_State *L, int stacksize); +LUA_API void lua_closethread (lua_State *L, lua_State *thread); /* @@ -215,8 +217,6 @@ LUA_API void lua_newuserdatabox (lua_State *L, void *u); ** =============================================================== */ -#define lua_open(n) lua_newthread(NULL, (n)) - #define lua_pop(L,n) lua_settop(L, -(n)-1) #define lua_register(L,n,f) (lua_pushcfunction(L, f), lua_setglobal(L, n))