commit 96e15b8501e5d8fc40c475cbac573f910ab5853b
parent 0fd91b1b087b478fffa36f96bc0f608d86627a4b
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Fri, 25 Oct 2002 17:05:06 -0300
threads now are real Lua objects, subject to garbage collection
Diffstat:
M | lapi.c | | | 20 | +++++++++++++++++++- |
M | lbaselib.c | | | 76 | ++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
M | ldo.c | | | 26 | ++++++++++++++++---------- |
M | lgc.c | | | 89 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
M | lobject.h | | | 67 | +++++++++++++++++++++++++++++-------------------------------------- |
M | lstate.c | | | 103 | ++++++++++++++++++++++++++++++++++++++++--------------------------------------- |
M | lstate.h | | | 31 | ++++++++++++++++++++----------- |
M | ltests.c | | | 7 | +++---- |
M | ltests.h | | | 11 | ++++++----- |
M | ltm.c | | | 4 | ++-- |
M | lua.h | | | 5 | +++-- |
M | lvm.c | | | 11 | ++++++----- |
12 files changed, 246 insertions(+), 204 deletions(-)
diff --git 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
@@ -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 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 gc_coroutine (lua_State *L) {
- lua_State *co = (lua_State *)lua_unboxpointer(L, 1);
- lua_closethread(L, co);
- return 0;
+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_coroutine (lua_State *L) {
+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; i<n; i++) {
+ for (i = 1; i <= n; i++) {
+ lua_pushvalue(L, i);
ref = lua_ref(L, 1);
lua_getref(NL, ref);
- lua_insert(NL, 1);
lua_unref(L, ref);
}
lua_cobegin(NL, n-1);
- lua_boxpointer(L, NL);
- lua_pushliteral(L, "Coroutine");
- lua_rawget(L, LUA_REGISTRYINDEX);
- lua_setmetatable(L, -2);
- lua_pushcclosure(L, luaB_resume, 1);
+ return 1;
+}
+
+
+static int luaB_cowrap (lua_State *L) {
+ luaB_cocreate(L);
+ lua_pushcclosure(L, luaB_auxwrap, 1);
return 1;
}
@@ -585,23 +603,13 @@ static int luaB_yield (lua_State *L) {
}
static const luaL_reg co_funcs[] = {
- {"create", luaB_coroutine},
+ {"create", luaB_cocreate},
+ {"wrap", luaB_cowrap},
+ {"resume", luaB_coresume},
{"yield", luaB_yield},
{NULL, NULL}
};
-
-static void co_open (lua_State *L) {
- luaL_opennamedlib(L, LUA_COLIBNAME, co_funcs, 0);
- /* create metatable for coroutines */
- lua_pushliteral(L, "Coroutine");
- lua_newtable(L);
- lua_pushliteral(L, "__gc");
- lua_pushcfunction(L, gc_coroutine);
- lua_rawset(L, -3);
- lua_rawset(L, LUA_REGISTRYINDEX);
-}
-
/* }====================================================== */
@@ -625,7 +633,7 @@ static void base_open (lua_State *L) {
LUALIB_API int lua_baselibopen (lua_State *L) {
base_open(L);
- co_open(L);
+ luaL_opennamedlib(L, LUA_COLIBNAME, co_funcs, 0);
lua_newtable(L);
lua_setglobal(L, REQTAB);
return 0;
diff --git a/ldo.c b/ldo.c
@@ -1,5 +1,5 @@
/*
-** $Id: ldo.c,v 1.195 2002/10/08 18:46:08 roberto Exp roberto $
+** $Id: ldo.c,v 1.196 2002/10/09 13:42:01 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@@ -343,16 +343,22 @@ LUA_API int lua_resume (lua_State *L, lua_State *co) {
int status;
lua_lock(L);
ci = co->ci;
- 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
@@ -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; o<L1->top; 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,46 +141,11 @@ static void reallymarkobject (GCState *st, GCObject *o) {
st->tmark = &o->h;
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; o<L1->top; 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;
+ case LUA_TTHREAD: {
+ markstack(st, &o->th);
+ break;
}
- 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));
+ }
}
@@ -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
@@ -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
/*
@@ -24,22 +24,33 @@
/*
+** 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<<p means tagmethod(p) is not present */
lu_byte mode;
lu_byte lsizenode; /* log2 of size of `node' array */
@@ -298,19 +302,6 @@ typedef struct Table {
#define sizearray(t) ((t)->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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);