From 96e15b8501e5d8fc40c475cbac573f910ab5853b Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 25 Oct 2002 17:05:28 -0300 Subject: [PATCH] threads now are real Lua objects, subject to garbage collection --- lapi.c | 20 ++++++++++- lbaselib.c | 78 ++++++++++++++++++++++------------------ ldo.c | 26 ++++++++------ lgc.c | 89 ++++++++++++++++++++++++--------------------- lobject.h | 67 +++++++++++++++------------------- lstate.c | 103 +++++++++++++++++++++++++++-------------------------- lstate.h | 31 ++++++++++------ ltests.c | 7 ++-- ltests.h | 11 +++--- ltm.c | 4 +-- lua.h | 5 +-- lvm.c | 11 +++--- 12 files changed, 247 insertions(+), 205 deletions(-) diff --git a/lapi.c b/lapi.c index a74c84fd..fbc122df 100644 --- a/lapi.c +++ b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 1.212 2002/08/30 19:09:21 roberto Exp roberto $ +** $Id: lapi.c,v 1.213 2002/09/20 17:01:24 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -115,6 +115,18 @@ LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) { } +LUA_API lua_State *lua_newthread (lua_State *L) { + lua_State *L1; + lua_lock(L); + L1 = luaE_newthread(L); + setthvalue(L->top, L1); + api_incr_top(L); + lua_unlock(L); + lua_userstateopen(L1); + return L1; +} + + /* ** basic stack manipulation */ @@ -322,6 +334,12 @@ LUA_API void *lua_touserdata (lua_State *L, int index) { } +LUA_API lua_State *lua_tothread (lua_State *L, int index) { + StkId o = luaA_indexAcceptable(L, index); + return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o); +} + + LUA_API const void *lua_topointer (lua_State *L, int index) { StkId o = luaA_indexAcceptable(L, index); if (o == NULL) return NULL; diff --git a/lbaselib.c b/lbaselib.c index 4ef2cb3e..1d8f8abf 100644 --- a/lbaselib.c +++ b/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.99 2002/09/16 19:49:45 roberto Exp roberto $ +** $Id: lbaselib.c,v 1.100 2002/10/22 19:41:08 roberto Exp roberto $ ** Basic library ** See Copyright Notice in lua.h */ @@ -362,6 +362,9 @@ static int luaB_tostring (lua_State *L) { case LUA_TLIGHTUSERDATA: sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); break; + case LUA_TTHREAD: + sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1)); + break; case LUA_TNIL: lua_pushliteral(L, "nil"); return 1; @@ -535,26 +538,40 @@ static const luaL_reg base_funcs[] = { */ -static int luaB_resume (lua_State *L) { - lua_State *co = (lua_State *)lua_unboxpointer(L, lua_upvalueindex(1)); +static int luaB_auxresume (lua_State *L, lua_State *co) { int status; - lua_settop(L, 0); + int oldtop = lua_gettop(L); status = lua_resume(L, co); - if (status != 0) - return lua_error(L); - return lua_gettop(L); + return (status != 0) ? -1 : lua_gettop(L) - oldtop; } - -static int gc_coroutine (lua_State *L) { - lua_State *co = (lua_State *)lua_unboxpointer(L, 1); - lua_closethread(L, co); - return 0; +static int luaB_coresume (lua_State *L) { + lua_State *co = lua_tothread(L, 1); + int r; + luaL_arg_check(L, co, 1, "coroutine/thread expected"); + r = luaB_auxresume(L, co); + if (r < 0) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + lua_insert(L, -(r + 1)); + return r + 1; /* return true + `resume' returns */ + } } -static int luaB_coroutine (lua_State *L) { +static int luaB_auxwrap (lua_State *L) { + int r = luaB_auxresume(L, lua_tothread(L, lua_upvalueindex(1))); + if (r < 0) lua_error(L); + return r; +} + + +static int luaB_cocreate (lua_State *L) { lua_State *NL; int ref; int i; @@ -562,20 +579,21 @@ static int luaB_coroutine (lua_State *L) { luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, "Lua function expected"); NL = lua_newthread(L); - if (NL == NULL) return luaL_error(L, "unable to create new thread"); /* move function and arguments from L to NL */ - for (i=0; ici; - if (ci == co->base_ci) /* no activation record? ?? */ - luaG_runerror(L, "cannot resume dead thread"); - if (co->errorJmp != NULL) /* ?? */ - luaG_runerror(L, "cannot resume active thread"); - status = luaD_rawrunprotected(co, resume, &numres); - if (status == 0) - move_results(L, co->top - numres, co->top); + if (ci == co->base_ci) { /* no activation record? ?? */ + luaO_pushfstring(L, "cannot resume dead thread"); + status = LUA_ERRRUN; + } + else if (co->errorJmp != NULL) { /* ?? */ + luaO_pushfstring(L, "cannot resume active thread"); + status = LUA_ERRRUN; + } else { - setobj(L->top++, co->top - 1); /* move error message to other stack */ - co->ci = co->base_ci; /* `kill' thread */ + status = luaD_rawrunprotected(co, resume, &numres); + if (status == 0) + move_results(L, co->top - numres, co->top); + else { + setobj(L->top++, co->top - 1); /* move error message to other stack */ + co->ci = co->base_ci; /* `kill' thread */ + } } lua_unlock(L); return status; diff --git a/lgc.c b/lgc.c index b7fc4c79..efa35cad 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 1.152 2002/10/08 18:46:08 roberto Exp roberto $ +** $Id: lgc.c,v 1.153 2002/10/22 17:58:14 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -99,6 +99,32 @@ static void markclosure (GCState *st, Closure *cl) { } +static void checkstacksizes (lua_State *L, StkId max) { + int used = L->ci - L->base_ci; /* number of `ci' in use */ + if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) + luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ + used = max - L->stack; /* part of stack in use */ + if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) + luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ +} + + +static void markstack (GCState *st, lua_State *L1) { + StkId o, lim; + CallInfo *ci; + markobject(st, gt(L1)); + for (o=L1->stack; otop; o++) + markobject(st, o); + lim = o; + for (ci = L1->base_ci; ci <= L1->ci; ci++) { + lua_assert(ci->top <= L1->stack_last); + if (lim < ci->top) lim = ci->top; + } + for (; o<=lim; o++) setnilvalue(o); + checkstacksizes(L1, lim); +} + + static void reallymarkobject (GCState *st, GCObject *o) { setbit(o->gch.marked, 0); /* mark object */ switch (o->gch.tt) { @@ -115,49 +141,14 @@ static void reallymarkobject (GCState *st, GCObject *o) { st->tmark = &o->h; break; } + case LUA_TTHREAD: { + markstack(st, &o->th); + break; + } } } -static void checkstacksizes (lua_State *L, StkId max) { - int used = L->ci - L->base_ci; /* number of `ci' in use */ - if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci) - luaD_reallocCI(L, L->size_ci/2); /* still big enough... */ - used = max - L->stack; /* part of stack in use */ - if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize) - luaD_reallocstack(L, L->stacksize/2); /* still big enough... */ -} - - -static void traversestacks (GCState *st) { - lua_State *L1 = st->L; - do { /* for each thread */ - StkId o, lim; - CallInfo *ci; - if (ttisnil(gt(L1))) { /* incomplete state? */ - lua_assert(L1 != st->L); - L1 = L1->next; - luaE_closethread(st->L, L1->previous); /* collect it */ - continue; - } - markobject(st, gt(L1)); - for (o=L1->stack; otop; o++) - markobject(st, o); - lim = o; - for (ci = L1->base_ci; ci <= L1->ci; ci++) { - lua_assert(ci->top <= L1->stack_last); - if (lim < ci->top) lim = ci->top; - } - for (; o<=lim; o++) setnilvalue(o); - checkstacksizes(L1, lim); - lua_assert(L1->previous->next == L1 && L1->next->previous == L1); - L1 = L1->next; - } while (L1 != st->L); - markobject(st, defaultmeta(L1)); - markobject(st, registry(L1)); -} - - static void marktmu (GCState *st) { GCObject *u; for (u = G(st->L)->tmudata; u; u = u->uv.next) @@ -292,6 +283,11 @@ static void freeobj (lua_State *L, GCObject *o) { case LUA_TFUNCTION: luaF_freeclosure(L, &o->cl); break; case LUA_TUPVAL: luaM_freelem(L, &o->uv); break; case LUA_TTABLE: luaH_free(L, &o->h); break; + case LUA_TTHREAD: { + lua_assert(&o->th != L && &o->th != G(L)->mainthread); + luaE_freethread(L, &o->th); + break; + } case LUA_TSTRING: { luaM_free(L, o, sizestring((&o->ts)->tsv.len)); break; @@ -389,13 +385,24 @@ void luaC_sweep (lua_State *L, int all) { } +/* mark root set */ +static void markroot (GCState *st) { + lua_State *L = st->L; + markobject(st, defaultmeta(L)); + markobject(st, registry(L)); + markstack(st, G(L)->mainthread); + if (L != G(L)->mainthread) /* another thread is running? */ + reallymarkobject(st, cast(GCObject *, L)); /* cannot collect it */ +} + + static void mark (lua_State *L) { GCState st; Table *toclear; st.L = L; st.tmark = NULL; st.toclear = NULL; - traversestacks(&st); /* mark all stacks */ + markroot(&st); propagatemarks(&st); /* mark all reachable objects */ toclear = st.toclear; /* weak tables; to be cleared */ st.toclear = NULL; diff --git a/lobject.h b/lobject.h index 580848aa..28edc661 100644 --- a/lobject.h +++ b/lobject.h @@ -1,5 +1,5 @@ /* -** $Id: lobject.h,v 1.148 2002/10/16 20:40:58 roberto Exp roberto $ +** $Id: lobject.h,v 1.149 2002/10/22 17:18:28 roberto Exp roberto $ ** Type definitions for Lua objects ** See Copyright Notice in lua.h */ @@ -13,7 +13,7 @@ /* tags for values visible from Lua */ -#define NUM_TAGS LUA_TUSERDATA +#define NUM_TAGS LUA_TTHREAD /* @@ -23,23 +23,34 @@ #define LUA_TUPVAL (NUM_TAGS+2) +/* +** Union of all collectable objects +*/ +typedef union GCObject GCObject; + + /* ** Common header for all collectable objects */ typedef struct GCheader { - union GCObject *next; /* pointer to next object */ + GCObject *next; /* pointer to next object */ lu_byte tt; /* object type */ lu_byte marked; /* GC informations */ } GCheader; +/* +** common header in macro form, to be included in other objects +*/ +#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked + /* ** Union of all Lua values */ typedef union { - union GCObject *gc; + GCObject *gc; void *p; lua_Number n; int b; @@ -63,6 +74,7 @@ typedef struct lua_TObject { #define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) #define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) #define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) +#define ttisthread(o) (ttype(o) == LUA_TTHREAD) #define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) /* Macros to access values */ @@ -75,6 +87,7 @@ typedef struct lua_TObject { #define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) #define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) #define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) +#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th) #define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) @@ -101,6 +114,11 @@ typedef struct lua_TObject { i_o->value.gc=cast(GCObject *, (x)); \ lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); } +#define setthvalue(obj,x) \ + { TObject *i_o=(obj); i_o->tt=LUA_TTHREAD; \ + i_o->value.gc=cast(GCObject *, (x)); \ + lua_assert(i_o->value.gc->gch.tt == LUA_TTHREAD); } + #define setclvalue(obj,x) \ { TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \ i_o->value.gc=cast(GCObject *, (x)); \ @@ -142,9 +160,7 @@ typedef TObject *StkId; /* index to stack elements */ typedef union TString { L_Umaxalign dummy; /* ensures maximum alignment for strings */ struct { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; lu_byte reserved; lu_hash hash; size_t len; @@ -160,9 +176,7 @@ typedef union TString { typedef union Udata { L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ struct { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; struct Table *metatable; size_t len; } uv; @@ -175,9 +189,7 @@ typedef union Udata { ** Function Prototypes */ typedef struct Proto { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; TObject *k; /* constants used by the function */ Instruction *code; struct Proto **p; /* functions defined inside the function */ @@ -210,9 +222,7 @@ typedef struct LocVar { */ typedef struct UpVal { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; TObject *v; /* points to stack or to its own value */ TObject value; /* the value (when closed) */ } UpVal; @@ -223,9 +233,7 @@ typedef struct UpVal { */ typedef struct CClosure { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; lu_byte isC; /* 0 for Lua functions, 1 for C functions */ lu_byte nupvalues; lua_CFunction f; @@ -234,9 +242,7 @@ typedef struct CClosure { typedef struct LClosure { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; lu_byte isC; lu_byte nupvalues; /* first five fields must be equal to CClosure!! */ struct Proto *p; @@ -267,9 +273,7 @@ typedef struct Node { typedef struct Table { - union GCObject *next; /* pointer to next object */ - lu_byte tt; /* object type */ - lu_byte marked; /* GC informations */ + CommonHeader; lu_byte flags; /* 1<

sizearray) -/* -** Union of all collectable objects -*/ -typedef union GCObject { - GCheader gch; - union TString ts; - union Udata u; - union Closure cl; - struct Table h; - struct Proto p; - struct UpVal uv; -} GCObject; - extern const TObject luaO_nilobject; diff --git a/lstate.c b/lstate.c index 58631289..cac3293b 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 1.106 2002/10/08 18:46:08 roberto Exp roberto $ +** $Id: lstate.c,v 1.107 2002/10/22 17:58:14 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -19,11 +19,30 @@ #include "ltm.h" +/* +** macro to allow the inclusion of user information in Lua state +*/ +#ifndef LUA_USERSTATE +#define EXTRASPACE 0 +#else +union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; +#define EXTRASPACE (sizeof(UEXTRASPACE)) +#endif static void close_state (lua_State *L); +static lua_State *newthread (lua_State *L) { + lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE); + if (block == NULL) return NULL; + else { + block += EXTRASPACE; + return cast(lua_State *, block); + } +} + + /* ** you can change this function through the official API: ** call `lua_setpanicf' @@ -34,19 +53,19 @@ static int default_panic (lua_State *L) { } -static void stack_init (lua_State *L, lua_State *OL) { - L->stack = luaM_newvector(OL, BASIC_STACK_SIZE + EXTRA_STACK, TObject); - L->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; - L->top = L->stack; - L->stack_last = L->stack+(L->stacksize - EXTRA_STACK)-1; - L->base_ci = luaM_newvector(OL, BASIC_CI_SIZE, CallInfo); - L->ci = L->base_ci; - L->ci->state = CI_C; /* not a Lua function */ - setnilvalue(L->top++); /* `function' entry for this `ci' */ - L->ci->base = L->top; - L->ci->top = L->top + LUA_MINSTACK; - L->size_ci = BASIC_CI_SIZE; - L->end_ci = L->base_ci + L->size_ci; +static void stack_init (lua_State *L1, lua_State *L) { + L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject); + L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; + L1->top = L1->stack; + L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1; + L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo); + L1->ci = L1->base_ci; + L1->ci->state = CI_C; /* not a Lua function */ + setnilvalue(L1->top++); /* `function' entry for this `ci' */ + L1->ci->base = L1->top; + L1->ci->top = L1->top + LUA_MINSTACK; + L1->size_ci = BASIC_CI_SIZE; + L1->end_ci = L1->base_ci + L1->size_ci; } @@ -57,6 +76,7 @@ static void f_luaopen (lua_State *L, void *ud) { UNUSED(ud); /* create a new global state */ L->l_G = luaM_new(L, global_State); + G(L)->mainthread = L; G(L)->GCthreshold = 0; /* mark it as unfinished state */ G(L)->strt.size = 0; G(L)->strt.nuse = 0; @@ -103,31 +123,22 @@ static void preinit_state (lua_State *L) { } -LUA_API lua_State *lua_newthread (lua_State *OL) { - lua_State *L; - lua_lock(OL); - L = luaM_new(OL, lua_State); - preinit_state(L); - L->l_G = OL->l_G; - OL->next->previous = L; /* insert L into linked list */ - L->next = OL->next; - OL->next = L; - L->previous = OL; - stack_init(L, OL); /* init stack */ - setobj(gt(L), gt(OL)); /* share table of globals */ - lua_unlock(OL); - lua_userstateopen(L); - return L; +lua_State *luaE_newthread (lua_State *L) { + lua_State *L1 = newthread(L); + luaC_link(L, cast(GCObject *, L1), LUA_TTHREAD); + preinit_state(L1); + L1->l_G = L->l_G; + stack_init(L1, L); /* init stack */ + setobj(gt(L1), gt(L)); /* share table of globals */ + return L1; } LUA_API lua_State *lua_open (void) { - lua_State *L; - L = luaM_new(NULL, lua_State); + lua_State *L = newthread(NULL); if (L) { /* allocation OK? */ preinit_state(L); L->l_G = NULL; - L->next = L->previous = L; if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { /* memory allocation error: free partial state */ close_state(L); @@ -139,14 +150,13 @@ LUA_API lua_State *lua_open (void) { } -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); - 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); +void luaE_freethread (lua_State *L, lua_State *L1) { + luaF_close(L1, L1->stack); /* close all upvalues for this thread */ + lua_assert(L1->openupval == NULL); + luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo); + luaM_freearray(L, L1->stack, L1->stacksize, TObject); + luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE, + sizeof(lua_State) + EXTRASPACE); } @@ -160,24 +170,15 @@ static void close_state (lua_State *L) { luaZ_freebuffer(L, &G(L)->buff); luaM_freelem(NULL, L->l_G); } - luaE_closethread(NULL, L); -} - - -LUA_API void lua_closethread (lua_State *L, lua_State *thread) { - lua_lock(L); - if (L == thread) luaG_runerror(L, "cannot close only thread of a state"); - luaE_closethread(L, thread); - lua_unlock(L); + luaE_freethread(NULL, L); } LUA_API void lua_close (lua_State *L) { lua_lock(L); + L = G(L)->mainthread; /* only the main thread can be closed */ 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 a54ffa62..9d88de6c 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 1.97 2002/10/08 18:46:08 roberto Exp roberto $ +** $Id: lstate.h,v 1.98 2002/10/22 17:58:14 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -32,12 +32,6 @@ #define lua_unlock(L) ((void) 0) #endif -/* -** macro to allow the inclusion of user information in Lua state -*/ -#ifndef LUA_USERSTATE -#define LUA_USERSTATE -#endif #ifndef lua_userstateopen #define lua_userstateopen(l) @@ -124,6 +118,7 @@ typedef struct global_State { lua_CFunction panic; /* to be called in unprotected errors */ TObject _registry; TObject _defaultmeta; + struct lua_State *mainthread; Node dummynode[1]; /* common node array for all empty tables */ TString *tmname[TM_N]; /* array with tag-method names */ } global_State; @@ -133,7 +128,7 @@ typedef struct global_State { ** `per thread' state */ struct lua_State { - LUA_USERSTATE + CommonHeader; StkId top; /* first free slot in the stack */ global_State *l_G; CallInfo *ci; /* call info for current function */ @@ -150,15 +145,29 @@ struct lua_State { GCObject *openupval; /* list of open upvalues in this stack */ struct lua_longjmp *errorJmp; /* current error recover point */ ptrdiff_t errfunc; /* current error handling function (stack index) */ - lua_State *next; /* circular double linked list of states */ - lua_State *previous; }; #define G(L) (L->l_G) -void luaE_closethread (lua_State *OL, lua_State *L); +/* +** Union of all collectable objects +*/ +union GCObject { + GCheader gch; + union TString ts; + union Udata u; + union Closure cl; + struct Table h; + struct Proto p; + struct UpVal uv; + struct lua_State th; /* thread */ +}; + + +lua_State *luaE_newthread (lua_State *L); +void luaE_freethread (lua_State *L, lua_State *L1); #endif diff --git a/ltests.c b/ltests.c index 0a22f859..3571b537 100644 --- a/ltests.c +++ b/ltests.c @@ -1,5 +1,5 @@ /* -** $Id: ltests.c,v 1.136 2002/10/22 17:18:28 roberto Exp roberto $ +** $Id: ltests.c,v 1.137 2002/10/22 18:07:55 roberto Exp roberto $ ** Internal Module for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -403,7 +403,6 @@ static int doonnewstack (lua_State *L) { if (status == 0) status = lua_pcall(L1, 0, 0, 0); lua_pushnumber(L, status); - lua_closethread(L, L1); return 1; } @@ -423,7 +422,7 @@ static int d2s (lua_State *L) { static int newstate (lua_State *L) { lua_State *L1 = lua_open(); if (L1) { - *cast(int **, L1) = &islocked; /* initialize the lock */ + lua_userstateopen(L1); /* init lock */ lua_pushnumber(L, (unsigned long)L1); } else @@ -724,7 +723,7 @@ static void fim (void) { int luaB_opentests (lua_State *L) { - *cast(int **, L) = &islocked; /* init lock */ + lua_userstateopen(L); /* init lock */ lua_state = L; /* keep first state to be opened */ luaL_opennamedlib(L, "T", tests_funcs, 0); atexit(fim); diff --git a/ltests.h b/ltests.h index 12ad9dcf..885d9235 100644 --- a/ltests.h +++ b/ltests.h @@ -1,5 +1,5 @@ /* -** $Id: ltests.h,v 1.15 2002/07/17 16:25:13 roberto Exp roberto $ +** $Id: ltests.h,v 1.16 2002/10/08 18:45:07 roberto Exp roberto $ ** Internal Header for Debugging of the Lua Implementation ** See Copyright Notice in lua.h */ @@ -42,10 +42,11 @@ void *debug_realloc (void *block, size_t oldsize, size_t size); /* test for lock/unlock */ extern int islocked; -#define LUA_USERSTATE int *lock; -#define lua_userstateopen(l) if (l != NULL) *cast(int **, l) = &islocked; -#define lua_lock(L) lua_assert((**cast(int **, L))++ == 0) -#define lua_unlock(L) lua_assert(--(**cast(int **, L)) == 0) +#define LUA_USERSTATE int * +#define getlock(l) (*(cast(int **, l) - 1)) +#define lua_userstateopen(l) if (l != NULL) getlock(l) = &islocked; +#define lua_lock(l) lua_assert((*getlock(l))++ == 0) +#define lua_unlock(l) lua_assert(--(*getlock(l)) == 0) int luaB_opentests (lua_State *L); diff --git a/ltm.c b/ltm.c index 8270b3e3..ff66afdd 100644 --- a/ltm.c +++ b/ltm.c @@ -1,5 +1,5 @@ /* -** $Id: ltm.c,v 1.101 2002/08/30 19:09:21 roberto Exp roberto $ +** $Id: ltm.c,v 1.102 2002/09/19 20:12:47 roberto Exp roberto $ ** Tag methods ** See Copyright Notice in lua.h */ @@ -19,7 +19,7 @@ const char *const luaT_typenames[] = { "nil", "boolean", "userdata", "number", - "string", "table", "function", "userdata" + "string", "table", "function", "userdata", "thread" }; diff --git a/lua.h b/lua.h index bc899b0c..f95ef4fd 100644 --- a/lua.h +++ b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.158 2002/10/22 17:18:28 roberto Exp roberto $ +** $Id: lua.h,v 1.159 2002/10/22 17:21:25 roberto Exp roberto $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -70,6 +70,7 @@ typedef const char * (*lua_Chunkreader) (lua_State *L, void *ud, size_t *sz); #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 /* minimum Lua stack available to a C function */ @@ -104,7 +105,6 @@ typedef LUA_NUMBER lua_Number; LUA_API lua_State *lua_open (void); LUA_API void lua_close (lua_State *L); LUA_API lua_State *lua_newthread (lua_State *L); -LUA_API void lua_closethread (lua_State *L, lua_State *t); LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf); @@ -142,6 +142,7 @@ LUA_API const char *lua_tostring (lua_State *L, int idx); LUA_API size_t lua_strlen (lua_State *L, int idx); LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); LUA_API void *lua_touserdata (lua_State *L, int idx); +LUA_API lua_State *lua_tothread (lua_State *L, int idx); LUA_API const void *lua_topointer (lua_State *L, int idx); diff --git a/lvm.c b/lvm.c index 68e6a080..8b72ae92 100644 --- a/lvm.c +++ b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 1.256 2002/09/19 20:12:47 roberto Exp roberto $ +** $Id: lvm.c,v 1.257 2002/10/08 18:46:08 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -263,22 +263,23 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) { switch (ttype(t1)) { case LUA_TNIL: return 1; case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); - case LUA_TSTRING: return tsvalue(t1) == tsvalue(t2); case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); - case LUA_TFUNCTION: return clvalue(t1) == clvalue(t2); - case LUA_TUSERDATA: + case LUA_TUSERDATA: { if (uvalue(t1) == uvalue(t2)) return 1; else if ((tm = fasttm(L, uvalue(t1)->uv.metatable, TM_EQ)) == NULL && (tm = fasttm(L, uvalue(t2)->uv.metatable, TM_EQ)) == NULL) return 0; /* no TM */ else break; /* will try TM */ - case LUA_TTABLE: + } + case LUA_TTABLE: { if (hvalue(t1) == hvalue(t2)) return 1; else if ((tm = fasttm(L, hvalue(t1)->metatable, TM_EQ)) == NULL && (tm = fasttm(L, hvalue(t2)->metatable, TM_EQ)) == NULL) return 0; /* no TM */ else break; /* will try TM */ + } + default: return gcvalue(t1) == gcvalue(t2); } callTMres(L, tm, t1, t2); /* call TM */ return !l_isfalse(L->top);