aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lapi.c20
-rw-r--r--lbaselib.c76
-rw-r--r--ldo.c26
-rw-r--r--lgc.c89
-rw-r--r--lobject.h67
-rw-r--r--lstate.c103
-rw-r--r--lstate.h31
-rw-r--r--ltests.c7
-rw-r--r--ltests.h11
-rw-r--r--ltm.c4
-rw-r--r--lua.h5
-rw-r--r--lvm.c11
12 files changed, 246 insertions, 204 deletions
diff --git a/lapi.c b/lapi.c
index a74c84fd..fbc122df 100644
--- a/lapi.c
+++ b/lapi.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lapi.c,v 1.212 2002/08/30 19:09:21 roberto Exp roberto $ 2** $Id: lapi.c,v 1.213 2002/09/20 17:01:24 roberto Exp roberto $
3** Lua API 3** Lua API
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -115,6 +115,18 @@ LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf) {
115} 115}
116 116
117 117
118LUA_API lua_State *lua_newthread (lua_State *L) {
119 lua_State *L1;
120 lua_lock(L);
121 L1 = luaE_newthread(L);
122 setthvalue(L->top, L1);
123 api_incr_top(L);
124 lua_unlock(L);
125 lua_userstateopen(L1);
126 return L1;
127}
128
129
118/* 130/*
119** basic stack manipulation 131** basic stack manipulation
120*/ 132*/
@@ -322,6 +334,12 @@ LUA_API void *lua_touserdata (lua_State *L, int index) {
322} 334}
323 335
324 336
337LUA_API lua_State *lua_tothread (lua_State *L, int index) {
338 StkId o = luaA_indexAcceptable(L, index);
339 return (o == NULL || !ttisthread(o)) ? NULL : thvalue(o);
340}
341
342
325LUA_API const void *lua_topointer (lua_State *L, int index) { 343LUA_API const void *lua_topointer (lua_State *L, int index) {
326 StkId o = luaA_indexAcceptable(L, index); 344 StkId o = luaA_indexAcceptable(L, index);
327 if (o == NULL) return NULL; 345 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 @@
1/* 1/*
2** $Id: lbaselib.c,v 1.99 2002/09/16 19:49:45 roberto Exp roberto $ 2** $Id: lbaselib.c,v 1.100 2002/10/22 19:41:08 roberto Exp roberto $
3** Basic library 3** Basic library
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -362,6 +362,9 @@ static int luaB_tostring (lua_State *L) {
362 case LUA_TLIGHTUSERDATA: 362 case LUA_TLIGHTUSERDATA:
363 sprintf(buff, "userdata: %p", lua_touserdata(L, 1)); 363 sprintf(buff, "userdata: %p", lua_touserdata(L, 1));
364 break; 364 break;
365 case LUA_TTHREAD:
366 sprintf(buff, "thread: %p", (void *)lua_tothread(L, 1));
367 break;
365 case LUA_TNIL: 368 case LUA_TNIL:
366 lua_pushliteral(L, "nil"); 369 lua_pushliteral(L, "nil");
367 return 1; 370 return 1;
@@ -535,26 +538,40 @@ static const luaL_reg base_funcs[] = {
535*/ 538*/
536 539
537 540
538static int luaB_resume (lua_State *L) { 541static int luaB_auxresume (lua_State *L, lua_State *co) {
539 lua_State *co = (lua_State *)lua_unboxpointer(L, lua_upvalueindex(1));
540 int status; 542 int status;
541 lua_settop(L, 0); 543 int oldtop = lua_gettop(L);
542 status = lua_resume(L, co); 544 status = lua_resume(L, co);
543 if (status != 0) 545 return (status != 0) ? -1 : lua_gettop(L) - oldtop;
544 return lua_error(L);
545 return lua_gettop(L);
546} 546}
547 547
548 548
549static int luaB_coresume (lua_State *L) {
550 lua_State *co = lua_tothread(L, 1);
551 int r;
552 luaL_arg_check(L, co, 1, "coroutine/thread expected");
553 r = luaB_auxresume(L, co);
554 if (r < 0) {
555 lua_pushboolean(L, 0);
556 lua_insert(L, -2);
557 return 2; /* return false + error message */
558 }
559 else {
560 lua_pushboolean(L, 1);
561 lua_insert(L, -(r + 1));
562 return r + 1; /* return true + `resume' returns */
563 }
564}
565
549 566
550static int gc_coroutine (lua_State *L) { 567static int luaB_auxwrap (lua_State *L) {
551 lua_State *co = (lua_State *)lua_unboxpointer(L, 1); 568 int r = luaB_auxresume(L, lua_tothread(L, lua_upvalueindex(1)));
552 lua_closethread(L, co); 569 if (r < 0) lua_error(L);
553 return 0; 570 return r;
554} 571}
555 572
556 573
557static int luaB_coroutine (lua_State *L) { 574static int luaB_cocreate (lua_State *L) {
558 lua_State *NL; 575 lua_State *NL;
559 int ref; 576 int ref;
560 int i; 577 int i;
@@ -562,20 +579,21 @@ static int luaB_coroutine (lua_State *L) {
562 luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1, 579 luaL_arg_check(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
563 "Lua function expected"); 580 "Lua function expected");
564 NL = lua_newthread(L); 581 NL = lua_newthread(L);
565 if (NL == NULL) return luaL_error(L, "unable to create new thread");
566 /* move function and arguments from L to NL */ 582 /* move function and arguments from L to NL */
567 for (i=0; i<n; i++) { 583 for (i = 1; i <= n; i++) {
584 lua_pushvalue(L, i);
568 ref = lua_ref(L, 1); 585 ref = lua_ref(L, 1);
569 lua_getref(NL, ref); 586 lua_getref(NL, ref);
570 lua_insert(NL, 1);
571 lua_unref(L, ref); 587 lua_unref(L, ref);
572 } 588 }
573 lua_cobegin(NL, n-1); 589 lua_cobegin(NL, n-1);
574 lua_boxpointer(L, NL); 590 return 1;
575 lua_pushliteral(L, "Coroutine"); 591}
576 lua_rawget(L, LUA_REGISTRYINDEX); 592
577 lua_setmetatable(L, -2); 593
578 lua_pushcclosure(L, luaB_resume, 1); 594static int luaB_cowrap (lua_State *L) {
595 luaB_cocreate(L);
596 lua_pushcclosure(L, luaB_auxwrap, 1);
579 return 1; 597 return 1;
580} 598}
581 599
@@ -585,23 +603,13 @@ static int luaB_yield (lua_State *L) {
585} 603}
586 604
587static const luaL_reg co_funcs[] = { 605static const luaL_reg co_funcs[] = {
588 {"create", luaB_coroutine}, 606 {"create", luaB_cocreate},
607 {"wrap", luaB_cowrap},
608 {"resume", luaB_coresume},
589 {"yield", luaB_yield}, 609 {"yield", luaB_yield},
590 {NULL, NULL} 610 {NULL, NULL}
591}; 611};
592 612
593
594static void co_open (lua_State *L) {
595 luaL_opennamedlib(L, LUA_COLIBNAME, co_funcs, 0);
596 /* create metatable for coroutines */
597 lua_pushliteral(L, "Coroutine");
598 lua_newtable(L);
599 lua_pushliteral(L, "__gc");
600 lua_pushcfunction(L, gc_coroutine);
601 lua_rawset(L, -3);
602 lua_rawset(L, LUA_REGISTRYINDEX);
603}
604
605/* }====================================================== */ 613/* }====================================================== */
606 614
607 615
@@ -625,7 +633,7 @@ static void base_open (lua_State *L) {
625 633
626LUALIB_API int lua_baselibopen (lua_State *L) { 634LUALIB_API int lua_baselibopen (lua_State *L) {
627 base_open(L); 635 base_open(L);
628 co_open(L); 636 luaL_opennamedlib(L, LUA_COLIBNAME, co_funcs, 0);
629 lua_newtable(L); 637 lua_newtable(L);
630 lua_setglobal(L, REQTAB); 638 lua_setglobal(L, REQTAB);
631 return 0; 639 return 0;
diff --git a/ldo.c b/ldo.c
index 15766e21..9ae6a116 100644
--- a/ldo.c
+++ b/ldo.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ldo.c,v 1.195 2002/10/08 18:46:08 roberto Exp roberto $ 2** $Id: ldo.c,v 1.196 2002/10/09 13:42:01 roberto Exp roberto $
3** Stack and Call structure of Lua 3** Stack and Call structure of Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -343,16 +343,22 @@ LUA_API int lua_resume (lua_State *L, lua_State *co) {
343 int status; 343 int status;
344 lua_lock(L); 344 lua_lock(L);
345 ci = co->ci; 345 ci = co->ci;
346 if (ci == co->base_ci) /* no activation record? ?? */ 346 if (ci == co->base_ci) { /* no activation record? ?? */
347 luaG_runerror(L, "cannot resume dead thread"); 347 luaO_pushfstring(L, "cannot resume dead thread");
348 if (co->errorJmp != NULL) /* ?? */ 348 status = LUA_ERRRUN;
349 luaG_runerror(L, "cannot resume active thread"); 349 }
350 status = luaD_rawrunprotected(co, resume, &numres); 350 else if (co->errorJmp != NULL) { /* ?? */
351 if (status == 0) 351 luaO_pushfstring(L, "cannot resume active thread");
352 move_results(L, co->top - numres, co->top); 352 status = LUA_ERRRUN;
353 }
353 else { 354 else {
354 setobj(L->top++, co->top - 1); /* move error message to other stack */ 355 status = luaD_rawrunprotected(co, resume, &numres);
355 co->ci = co->base_ci; /* `kill' thread */ 356 if (status == 0)
357 move_results(L, co->top - numres, co->top);
358 else {
359 setobj(L->top++, co->top - 1); /* move error message to other stack */
360 co->ci = co->base_ci; /* `kill' thread */
361 }
356 } 362 }
357 lua_unlock(L); 363 lua_unlock(L);
358 return status; 364 return status;
diff --git a/lgc.c b/lgc.c
index b7fc4c79..efa35cad 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 1.152 2002/10/08 18:46:08 roberto Exp roberto $ 2** $Id: lgc.c,v 1.153 2002/10/22 17:58:14 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -99,6 +99,32 @@ static void markclosure (GCState *st, Closure *cl) {
99} 99}
100 100
101 101
102static void checkstacksizes (lua_State *L, StkId max) {
103 int used = L->ci - L->base_ci; /* number of `ci' in use */
104 if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
105 luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
106 used = max - L->stack; /* part of stack in use */
107 if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
108 luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
109}
110
111
112static void markstack (GCState *st, lua_State *L1) {
113 StkId o, lim;
114 CallInfo *ci;
115 markobject(st, gt(L1));
116 for (o=L1->stack; o<L1->top; o++)
117 markobject(st, o);
118 lim = o;
119 for (ci = L1->base_ci; ci <= L1->ci; ci++) {
120 lua_assert(ci->top <= L1->stack_last);
121 if (lim < ci->top) lim = ci->top;
122 }
123 for (; o<=lim; o++) setnilvalue(o);
124 checkstacksizes(L1, lim);
125}
126
127
102static void reallymarkobject (GCState *st, GCObject *o) { 128static void reallymarkobject (GCState *st, GCObject *o) {
103 setbit(o->gch.marked, 0); /* mark object */ 129 setbit(o->gch.marked, 0); /* mark object */
104 switch (o->gch.tt) { 130 switch (o->gch.tt) {
@@ -115,46 +141,11 @@ static void reallymarkobject (GCState *st, GCObject *o) {
115 st->tmark = &o->h; 141 st->tmark = &o->h;
116 break; 142 break;
117 } 143 }
118 } 144 case LUA_TTHREAD: {
119} 145 markstack(st, &o->th);
120 146 break;
121
122static void checkstacksizes (lua_State *L, StkId max) {
123 int used = L->ci - L->base_ci; /* number of `ci' in use */
124 if (4*used < L->size_ci && 2*BASIC_CI_SIZE < L->size_ci)
125 luaD_reallocCI(L, L->size_ci/2); /* still big enough... */
126 used = max - L->stack; /* part of stack in use */
127 if (4*used < L->stacksize && 2*(BASIC_STACK_SIZE+EXTRA_STACK) < L->stacksize)
128 luaD_reallocstack(L, L->stacksize/2); /* still big enough... */
129}
130
131
132static void traversestacks (GCState *st) {
133 lua_State *L1 = st->L;
134 do { /* for each thread */
135 StkId o, lim;
136 CallInfo *ci;
137 if (ttisnil(gt(L1))) { /* incomplete state? */
138 lua_assert(L1 != st->L);
139 L1 = L1->next;
140 luaE_closethread(st->L, L1->previous); /* collect it */
141 continue;
142 }
143 markobject(st, gt(L1));
144 for (o=L1->stack; o<L1->top; o++)
145 markobject(st, o);
146 lim = o;
147 for (ci = L1->base_ci; ci <= L1->ci; ci++) {
148 lua_assert(ci->top <= L1->stack_last);
149 if (lim < ci->top) lim = ci->top;
150 } 147 }
151 for (; o<=lim; o++) setnilvalue(o); 148 }
152 checkstacksizes(L1, lim);
153 lua_assert(L1->previous->next == L1 && L1->next->previous == L1);
154 L1 = L1->next;
155 } while (L1 != st->L);
156 markobject(st, defaultmeta(L1));
157 markobject(st, registry(L1));
158} 149}
159 150
160 151
@@ -292,6 +283,11 @@ static void freeobj (lua_State *L, GCObject *o) {
292 case LUA_TFUNCTION: luaF_freeclosure(L, &o->cl); break; 283 case LUA_TFUNCTION: luaF_freeclosure(L, &o->cl); break;
293 case LUA_TUPVAL: luaM_freelem(L, &o->uv); break; 284 case LUA_TUPVAL: luaM_freelem(L, &o->uv); break;
294 case LUA_TTABLE: luaH_free(L, &o->h); break; 285 case LUA_TTABLE: luaH_free(L, &o->h); break;
286 case LUA_TTHREAD: {
287 lua_assert(&o->th != L && &o->th != G(L)->mainthread);
288 luaE_freethread(L, &o->th);
289 break;
290 }
295 case LUA_TSTRING: { 291 case LUA_TSTRING: {
296 luaM_free(L, o, sizestring((&o->ts)->tsv.len)); 292 luaM_free(L, o, sizestring((&o->ts)->tsv.len));
297 break; 293 break;
@@ -389,13 +385,24 @@ void luaC_sweep (lua_State *L, int all) {
389} 385}
390 386
391 387
388/* mark root set */
389static void markroot (GCState *st) {
390 lua_State *L = st->L;
391 markobject(st, defaultmeta(L));
392 markobject(st, registry(L));
393 markstack(st, G(L)->mainthread);
394 if (L != G(L)->mainthread) /* another thread is running? */
395 reallymarkobject(st, cast(GCObject *, L)); /* cannot collect it */
396}
397
398
392static void mark (lua_State *L) { 399static void mark (lua_State *L) {
393 GCState st; 400 GCState st;
394 Table *toclear; 401 Table *toclear;
395 st.L = L; 402 st.L = L;
396 st.tmark = NULL; 403 st.tmark = NULL;
397 st.toclear = NULL; 404 st.toclear = NULL;
398 traversestacks(&st); /* mark all stacks */ 405 markroot(&st);
399 propagatemarks(&st); /* mark all reachable objects */ 406 propagatemarks(&st); /* mark all reachable objects */
400 toclear = st.toclear; /* weak tables; to be cleared */ 407 toclear = st.toclear; /* weak tables; to be cleared */
401 st.toclear = NULL; 408 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 @@
1/* 1/*
2** $Id: lobject.h,v 1.148 2002/10/16 20:40:58 roberto Exp roberto $ 2** $Id: lobject.h,v 1.149 2002/10/22 17:18:28 roberto Exp roberto $
3** Type definitions for Lua objects 3** Type definitions for Lua objects
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -13,7 +13,7 @@
13 13
14 14
15/* tags for values visible from Lua */ 15/* tags for values visible from Lua */
16#define NUM_TAGS LUA_TUSERDATA 16#define NUM_TAGS LUA_TTHREAD
17 17
18 18
19/* 19/*
@@ -24,22 +24,33 @@
24 24
25 25
26/* 26/*
27** Union of all collectable objects
28*/
29typedef union GCObject GCObject;
30
31
32/*
27** Common header for all collectable objects 33** Common header for all collectable objects
28*/ 34*/
29typedef struct GCheader { 35typedef struct GCheader {
30 union GCObject *next; /* pointer to next object */ 36 GCObject *next; /* pointer to next object */
31 lu_byte tt; /* object type */ 37 lu_byte tt; /* object type */
32 lu_byte marked; /* GC informations */ 38 lu_byte marked; /* GC informations */
33} GCheader; 39} GCheader;
34 40
35 41
42/*
43** common header in macro form, to be included in other objects
44*/
45#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
46
36 47
37 48
38/* 49/*
39** Union of all Lua values 50** Union of all Lua values
40*/ 51*/
41typedef union { 52typedef union {
42 union GCObject *gc; 53 GCObject *gc;
43 void *p; 54 void *p;
44 lua_Number n; 55 lua_Number n;
45 int b; 56 int b;
@@ -63,6 +74,7 @@ typedef struct lua_TObject {
63#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION) 74#define ttisfunction(o) (ttype(o) == LUA_TFUNCTION)
64#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN) 75#define ttisboolean(o) (ttype(o) == LUA_TBOOLEAN)
65#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA) 76#define ttisuserdata(o) (ttype(o) == LUA_TUSERDATA)
77#define ttisthread(o) (ttype(o) == LUA_TTHREAD)
66#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA) 78#define ttislightuserdata(o) (ttype(o) == LUA_TLIGHTUSERDATA)
67 79
68/* Macros to access values */ 80/* Macros to access values */
@@ -75,6 +87,7 @@ typedef struct lua_TObject {
75#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl) 87#define clvalue(o) check_exp(ttisfunction(o), &(o)->value.gc->cl)
76#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h) 88#define hvalue(o) check_exp(ttistable(o), &(o)->value.gc->h)
77#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b) 89#define bvalue(o) check_exp(ttisboolean(o), (o)->value.b)
90#define thvalue(o) check_exp(ttisthread(o), &(o)->value.gc->th)
78 91
79#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0)) 92#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
80 93
@@ -101,6 +114,11 @@ typedef struct lua_TObject {
101 i_o->value.gc=cast(GCObject *, (x)); \ 114 i_o->value.gc=cast(GCObject *, (x)); \
102 lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); } 115 lua_assert(i_o->value.gc->gch.tt == LUA_TUSERDATA); }
103 116
117#define setthvalue(obj,x) \
118 { TObject *i_o=(obj); i_o->tt=LUA_TTHREAD; \
119 i_o->value.gc=cast(GCObject *, (x)); \
120 lua_assert(i_o->value.gc->gch.tt == LUA_TTHREAD); }
121
104#define setclvalue(obj,x) \ 122#define setclvalue(obj,x) \
105 { TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \ 123 { TObject *i_o=(obj); i_o->tt=LUA_TFUNCTION; \
106 i_o->value.gc=cast(GCObject *, (x)); \ 124 i_o->value.gc=cast(GCObject *, (x)); \
@@ -142,9 +160,7 @@ typedef TObject *StkId; /* index to stack elements */
142typedef union TString { 160typedef union TString {
143 L_Umaxalign dummy; /* ensures maximum alignment for strings */ 161 L_Umaxalign dummy; /* ensures maximum alignment for strings */
144 struct { 162 struct {
145 union GCObject *next; /* pointer to next object */ 163 CommonHeader;
146 lu_byte tt; /* object type */
147 lu_byte marked; /* GC informations */
148 lu_byte reserved; 164 lu_byte reserved;
149 lu_hash hash; 165 lu_hash hash;
150 size_t len; 166 size_t len;
@@ -160,9 +176,7 @@ typedef union TString {
160typedef union Udata { 176typedef union Udata {
161 L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */ 177 L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
162 struct { 178 struct {
163 union GCObject *next; /* pointer to next object */ 179 CommonHeader;
164 lu_byte tt; /* object type */
165 lu_byte marked; /* GC informations */
166 struct Table *metatable; 180 struct Table *metatable;
167 size_t len; 181 size_t len;
168 } uv; 182 } uv;
@@ -175,9 +189,7 @@ typedef union Udata {
175** Function Prototypes 189** Function Prototypes
176*/ 190*/
177typedef struct Proto { 191typedef struct Proto {
178 union GCObject *next; /* pointer to next object */ 192 CommonHeader;
179 lu_byte tt; /* object type */
180 lu_byte marked; /* GC informations */
181 TObject *k; /* constants used by the function */ 193 TObject *k; /* constants used by the function */
182 Instruction *code; 194 Instruction *code;
183 struct Proto **p; /* functions defined inside the function */ 195 struct Proto **p; /* functions defined inside the function */
@@ -210,9 +222,7 @@ typedef struct LocVar {
210*/ 222*/
211 223
212typedef struct UpVal { 224typedef struct UpVal {
213 union GCObject *next; /* pointer to next object */ 225 CommonHeader;
214 lu_byte tt; /* object type */
215 lu_byte marked; /* GC informations */
216 TObject *v; /* points to stack or to its own value */ 226 TObject *v; /* points to stack or to its own value */
217 TObject value; /* the value (when closed) */ 227 TObject value; /* the value (when closed) */
218} UpVal; 228} UpVal;
@@ -223,9 +233,7 @@ typedef struct UpVal {
223*/ 233*/
224 234
225typedef struct CClosure { 235typedef struct CClosure {
226 union GCObject *next; /* pointer to next object */ 236 CommonHeader;
227 lu_byte tt; /* object type */
228 lu_byte marked; /* GC informations */
229 lu_byte isC; /* 0 for Lua functions, 1 for C functions */ 237 lu_byte isC; /* 0 for Lua functions, 1 for C functions */
230 lu_byte nupvalues; 238 lu_byte nupvalues;
231 lua_CFunction f; 239 lua_CFunction f;
@@ -234,9 +242,7 @@ typedef struct CClosure {
234 242
235 243
236typedef struct LClosure { 244typedef struct LClosure {
237 union GCObject *next; /* pointer to next object */ 245 CommonHeader;
238 lu_byte tt; /* object type */
239 lu_byte marked; /* GC informations */
240 lu_byte isC; 246 lu_byte isC;
241 lu_byte nupvalues; /* first five fields must be equal to CClosure!! */ 247 lu_byte nupvalues; /* first five fields must be equal to CClosure!! */
242 struct Proto *p; 248 struct Proto *p;
@@ -267,9 +273,7 @@ typedef struct Node {
267 273
268 274
269typedef struct Table { 275typedef struct Table {
270 union GCObject *next; /* pointer to next object */ 276 CommonHeader;
271 lu_byte tt; /* object type */
272 lu_byte marked; /* GC informations */
273 lu_byte flags; /* 1<<p means tagmethod(p) is not present */ 277 lu_byte flags; /* 1<<p means tagmethod(p) is not present */
274 lu_byte mode; 278 lu_byte mode;
275 lu_byte lsizenode; /* log2 of size of `node' array */ 279 lu_byte lsizenode; /* log2 of size of `node' array */
@@ -298,19 +302,6 @@ typedef struct Table {
298#define sizearray(t) ((t)->sizearray) 302#define sizearray(t) ((t)->sizearray)
299 303
300 304
301/*
302** Union of all collectable objects
303*/
304typedef union GCObject {
305 GCheader gch;
306 union TString ts;
307 union Udata u;
308 union Closure cl;
309 struct Table h;
310 struct Proto p;
311 struct UpVal uv;
312} GCObject;
313
314 305
315extern const TObject luaO_nilobject; 306extern const TObject luaO_nilobject;
316 307
diff --git a/lstate.c b/lstate.c
index 58631289..cac3293b 100644
--- a/lstate.c
+++ b/lstate.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.c,v 1.106 2002/10/08 18:46:08 roberto Exp roberto $ 2** $Id: lstate.c,v 1.107 2002/10/22 17:58:14 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -19,11 +19,30 @@
19#include "ltm.h" 19#include "ltm.h"
20 20
21 21
22/*
23** macro to allow the inclusion of user information in Lua state
24*/
25#ifndef LUA_USERSTATE
26#define EXTRASPACE 0
27#else
28union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;};
29#define EXTRASPACE (sizeof(UEXTRASPACE))
30#endif
22 31
23 32
24static void close_state (lua_State *L); 33static void close_state (lua_State *L);
25 34
26 35
36static lua_State *newthread (lua_State *L) {
37 lu_byte *block = (lu_byte *)luaM_malloc(L, sizeof(lua_State) + EXTRASPACE);
38 if (block == NULL) return NULL;
39 else {
40 block += EXTRASPACE;
41 return cast(lua_State *, block);
42 }
43}
44
45
27/* 46/*
28** you can change this function through the official API: 47** you can change this function through the official API:
29** call `lua_setpanicf' 48** call `lua_setpanicf'
@@ -34,19 +53,19 @@ static int default_panic (lua_State *L) {
34} 53}
35 54
36 55
37static void stack_init (lua_State *L, lua_State *OL) { 56static void stack_init (lua_State *L1, lua_State *L) {
38 L->stack = luaM_newvector(OL, BASIC_STACK_SIZE + EXTRA_STACK, TObject); 57 L1->stack = luaM_newvector(L, BASIC_STACK_SIZE + EXTRA_STACK, TObject);
39 L->stacksize = BASIC_STACK_SIZE + EXTRA_STACK; 58 L1->stacksize = BASIC_STACK_SIZE + EXTRA_STACK;
40 L->top = L->stack; 59 L1->top = L1->stack;
41 L->stack_last = L->stack+(L->stacksize - EXTRA_STACK)-1; 60 L1->stack_last = L1->stack+(L1->stacksize - EXTRA_STACK)-1;
42 L->base_ci = luaM_newvector(OL, BASIC_CI_SIZE, CallInfo); 61 L1->base_ci = luaM_newvector(L, BASIC_CI_SIZE, CallInfo);
43 L->ci = L->base_ci; 62 L1->ci = L1->base_ci;
44 L->ci->state = CI_C; /* not a Lua function */ 63 L1->ci->state = CI_C; /* not a Lua function */
45 setnilvalue(L->top++); /* `function' entry for this `ci' */ 64 setnilvalue(L1->top++); /* `function' entry for this `ci' */
46 L->ci->base = L->top; 65 L1->ci->base = L1->top;
47 L->ci->top = L->top + LUA_MINSTACK; 66 L1->ci->top = L1->top + LUA_MINSTACK;
48 L->size_ci = BASIC_CI_SIZE; 67 L1->size_ci = BASIC_CI_SIZE;
49 L->end_ci = L->base_ci + L->size_ci; 68 L1->end_ci = L1->base_ci + L1->size_ci;
50} 69}
51 70
52 71
@@ -57,6 +76,7 @@ static void f_luaopen (lua_State *L, void *ud) {
57 UNUSED(ud); 76 UNUSED(ud);
58 /* create a new global state */ 77 /* create a new global state */
59 L->l_G = luaM_new(L, global_State); 78 L->l_G = luaM_new(L, global_State);
79 G(L)->mainthread = L;
60 G(L)->GCthreshold = 0; /* mark it as unfinished state */ 80 G(L)->GCthreshold = 0; /* mark it as unfinished state */
61 G(L)->strt.size = 0; 81 G(L)->strt.size = 0;
62 G(L)->strt.nuse = 0; 82 G(L)->strt.nuse = 0;
@@ -103,31 +123,22 @@ static void preinit_state (lua_State *L) {
103} 123}
104 124
105 125
106LUA_API lua_State *lua_newthread (lua_State *OL) { 126lua_State *luaE_newthread (lua_State *L) {
107 lua_State *L; 127 lua_State *L1 = newthread(L);
108 lua_lock(OL); 128 luaC_link(L, cast(GCObject *, L1), LUA_TTHREAD);
109 L = luaM_new(OL, lua_State); 129 preinit_state(L1);
110 preinit_state(L); 130 L1->l_G = L->l_G;
111 L->l_G = OL->l_G; 131 stack_init(L1, L); /* init stack */
112 OL->next->previous = L; /* insert L into linked list */ 132 setobj(gt(L1), gt(L)); /* share table of globals */
113 L->next = OL->next; 133 return L1;
114 OL->next = L;
115 L->previous = OL;
116 stack_init(L, OL); /* init stack */
117 setobj(gt(L), gt(OL)); /* share table of globals */
118 lua_unlock(OL);
119 lua_userstateopen(L);
120 return L;
121} 134}
122 135
123 136
124LUA_API lua_State *lua_open (void) { 137LUA_API lua_State *lua_open (void) {
125 lua_State *L; 138 lua_State *L = newthread(NULL);
126 L = luaM_new(NULL, lua_State);
127 if (L) { /* allocation OK? */ 139 if (L) { /* allocation OK? */
128 preinit_state(L); 140 preinit_state(L);
129 L->l_G = NULL; 141 L->l_G = NULL;
130 L->next = L->previous = L;
131 if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) { 142 if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
132 /* memory allocation error: free partial state */ 143 /* memory allocation error: free partial state */
133 close_state(L); 144 close_state(L);
@@ -139,14 +150,13 @@ LUA_API lua_State *lua_open (void) {
139} 150}
140 151
141 152
142void luaE_closethread (lua_State *OL, lua_State *L) { 153void luaE_freethread (lua_State *L, lua_State *L1) {
143 luaF_close(L, L->stack); /* close all upvalues for this thread */ 154 luaF_close(L1, L1->stack); /* close all upvalues for this thread */
144 lua_assert(L->openupval == NULL); 155 lua_assert(L1->openupval == NULL);
145 L->previous->next = L->next; 156 luaM_freearray(L, L1->base_ci, L1->size_ci, CallInfo);
146 L->next->previous = L->previous; 157 luaM_freearray(L, L1->stack, L1->stacksize, TObject);
147 luaM_freearray(OL, L->base_ci, L->size_ci, CallInfo); 158 luaM_free(L, cast(lu_byte *, L1) - EXTRASPACE,
148 luaM_freearray(OL, L->stack, L->stacksize, TObject); 159 sizeof(lua_State) + EXTRASPACE);
149 luaM_freelem(OL, L);
150} 160}
151 161
152 162
@@ -160,24 +170,15 @@ static void close_state (lua_State *L) {
160 luaZ_freebuffer(L, &G(L)->buff); 170 luaZ_freebuffer(L, &G(L)->buff);
161 luaM_freelem(NULL, L->l_G); 171 luaM_freelem(NULL, L->l_G);
162 } 172 }
163 luaE_closethread(NULL, L); 173 luaE_freethread(NULL, L);
164}
165
166
167LUA_API void lua_closethread (lua_State *L, lua_State *thread) {
168 lua_lock(L);
169 if (L == thread) luaG_runerror(L, "cannot close only thread of a state");
170 luaE_closethread(L, thread);
171 lua_unlock(L);
172} 174}
173 175
174 176
175LUA_API void lua_close (lua_State *L) { 177LUA_API void lua_close (lua_State *L) {
176 lua_lock(L); 178 lua_lock(L);
179 L = G(L)->mainthread; /* only the main thread can be closed */
177 luaC_callallgcTM(L); /* call GC tag methods for all udata */ 180 luaC_callallgcTM(L); /* call GC tag methods for all udata */
178 lua_assert(G(L)->tmudata == NULL); 181 lua_assert(G(L)->tmudata == NULL);
179 while (L->next != L) /* then, close all other threads */
180 luaE_closethread(L, L->next);
181 close_state(L); 182 close_state(L);
182} 183}
183 184
diff --git a/lstate.h b/lstate.h
index a54ffa62..9d88de6c 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 1.97 2002/10/08 18:46:08 roberto Exp roberto $ 2** $Id: lstate.h,v 1.98 2002/10/22 17:58:14 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -32,12 +32,6 @@
32#define lua_unlock(L) ((void) 0) 32#define lua_unlock(L) ((void) 0)
33#endif 33#endif
34 34
35/*
36** macro to allow the inclusion of user information in Lua state
37*/
38#ifndef LUA_USERSTATE
39#define LUA_USERSTATE
40#endif
41 35
42#ifndef lua_userstateopen 36#ifndef lua_userstateopen
43#define lua_userstateopen(l) 37#define lua_userstateopen(l)
@@ -124,6 +118,7 @@ typedef struct global_State {
124 lua_CFunction panic; /* to be called in unprotected errors */ 118 lua_CFunction panic; /* to be called in unprotected errors */
125 TObject _registry; 119 TObject _registry;
126 TObject _defaultmeta; 120 TObject _defaultmeta;
121 struct lua_State *mainthread;
127 Node dummynode[1]; /* common node array for all empty tables */ 122 Node dummynode[1]; /* common node array for all empty tables */
128 TString *tmname[TM_N]; /* array with tag-method names */ 123 TString *tmname[TM_N]; /* array with tag-method names */
129} global_State; 124} global_State;
@@ -133,7 +128,7 @@ typedef struct global_State {
133** `per thread' state 128** `per thread' state
134*/ 129*/
135struct lua_State { 130struct lua_State {
136 LUA_USERSTATE 131 CommonHeader;
137 StkId top; /* first free slot in the stack */ 132 StkId top; /* first free slot in the stack */
138 global_State *l_G; 133 global_State *l_G;
139 CallInfo *ci; /* call info for current function */ 134 CallInfo *ci; /* call info for current function */
@@ -150,15 +145,29 @@ struct lua_State {
150 GCObject *openupval; /* list of open upvalues in this stack */ 145 GCObject *openupval; /* list of open upvalues in this stack */
151 struct lua_longjmp *errorJmp; /* current error recover point */ 146 struct lua_longjmp *errorJmp; /* current error recover point */
152 ptrdiff_t errfunc; /* current error handling function (stack index) */ 147 ptrdiff_t errfunc; /* current error handling function (stack index) */
153 lua_State *next; /* circular double linked list of states */
154 lua_State *previous;
155}; 148};
156 149
157 150
158#define G(L) (L->l_G) 151#define G(L) (L->l_G)
159 152
160 153
161void luaE_closethread (lua_State *OL, lua_State *L); 154/*
155** Union of all collectable objects
156*/
157union GCObject {
158 GCheader gch;
159 union TString ts;
160 union Udata u;
161 union Closure cl;
162 struct Table h;
163 struct Proto p;
164 struct UpVal uv;
165 struct lua_State th; /* thread */
166};
167
168
169lua_State *luaE_newthread (lua_State *L);
170void luaE_freethread (lua_State *L, lua_State *L1);
162 171
163#endif 172#endif
164 173
diff --git a/ltests.c b/ltests.c
index 0a22f859..3571b537 100644
--- a/ltests.c
+++ b/ltests.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.c,v 1.136 2002/10/22 17:18:28 roberto Exp roberto $ 2** $Id: ltests.c,v 1.137 2002/10/22 18:07:55 roberto Exp roberto $
3** Internal Module for Debugging of the Lua Implementation 3** Internal Module for Debugging of the Lua Implementation
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -403,7 +403,6 @@ static int doonnewstack (lua_State *L) {
403 if (status == 0) 403 if (status == 0)
404 status = lua_pcall(L1, 0, 0, 0); 404 status = lua_pcall(L1, 0, 0, 0);
405 lua_pushnumber(L, status); 405 lua_pushnumber(L, status);
406 lua_closethread(L, L1);
407 return 1; 406 return 1;
408} 407}
409 408
@@ -423,7 +422,7 @@ static int d2s (lua_State *L) {
423static int newstate (lua_State *L) { 422static int newstate (lua_State *L) {
424 lua_State *L1 = lua_open(); 423 lua_State *L1 = lua_open();
425 if (L1) { 424 if (L1) {
426 *cast(int **, L1) = &islocked; /* initialize the lock */ 425 lua_userstateopen(L1); /* init lock */
427 lua_pushnumber(L, (unsigned long)L1); 426 lua_pushnumber(L, (unsigned long)L1);
428 } 427 }
429 else 428 else
@@ -724,7 +723,7 @@ static void fim (void) {
724 723
725 724
726int luaB_opentests (lua_State *L) { 725int luaB_opentests (lua_State *L) {
727 *cast(int **, L) = &islocked; /* init lock */ 726 lua_userstateopen(L); /* init lock */
728 lua_state = L; /* keep first state to be opened */ 727 lua_state = L; /* keep first state to be opened */
729 luaL_opennamedlib(L, "T", tests_funcs, 0); 728 luaL_opennamedlib(L, "T", tests_funcs, 0);
730 atexit(fim); 729 atexit(fim);
diff --git a/ltests.h b/ltests.h
index 12ad9dcf..885d9235 100644
--- a/ltests.h
+++ b/ltests.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: ltests.h,v 1.15 2002/07/17 16:25:13 roberto Exp roberto $ 2** $Id: ltests.h,v 1.16 2002/10/08 18:45:07 roberto Exp roberto $
3** Internal Header for Debugging of the Lua Implementation 3** Internal Header for Debugging of the Lua Implementation
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -42,10 +42,11 @@ void *debug_realloc (void *block, size_t oldsize, size_t size);
42 42
43/* test for lock/unlock */ 43/* test for lock/unlock */
44extern int islocked; 44extern int islocked;
45#define LUA_USERSTATE int *lock; 45#define LUA_USERSTATE int *
46#define lua_userstateopen(l) if (l != NULL) *cast(int **, l) = &islocked; 46#define getlock(l) (*(cast(int **, l) - 1))
47#define lua_lock(L) lua_assert((**cast(int **, L))++ == 0) 47#define lua_userstateopen(l) if (l != NULL) getlock(l) = &islocked;
48#define lua_unlock(L) lua_assert(--(**cast(int **, L)) == 0) 48#define lua_lock(l) lua_assert((*getlock(l))++ == 0)
49#define lua_unlock(l) lua_assert(--(*getlock(l)) == 0)
49 50
50 51
51int luaB_opentests (lua_State *L); 52int 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 @@
1/* 1/*
2** $Id: ltm.c,v 1.101 2002/08/30 19:09:21 roberto Exp roberto $ 2** $Id: ltm.c,v 1.102 2002/09/19 20:12:47 roberto Exp roberto $
3** Tag methods 3** Tag methods
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -19,7 +19,7 @@
19 19
20const char *const luaT_typenames[] = { 20const char *const luaT_typenames[] = {
21 "nil", "boolean", "userdata", "number", 21 "nil", "boolean", "userdata", "number",
22 "string", "table", "function", "userdata" 22 "string", "table", "function", "userdata", "thread"
23}; 23};
24 24
25 25
diff --git a/lua.h b/lua.h
index bc899b0c..f95ef4fd 100644
--- a/lua.h
+++ b/lua.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lua.h,v 1.158 2002/10/22 17:18:28 roberto Exp roberto $ 2** $Id: lua.h,v 1.159 2002/10/22 17:21:25 roberto Exp roberto $
3** Lua - An Extensible Extension Language 3** Lua - An Extensible Extension Language
4** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil 4** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil
5** http://www.lua.org mailto:info@lua.org 5** 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);
70#define LUA_TTABLE 5 70#define LUA_TTABLE 5
71#define LUA_TFUNCTION 6 71#define LUA_TFUNCTION 6
72#define LUA_TUSERDATA 7 72#define LUA_TUSERDATA 7
73#define LUA_TTHREAD 8
73 74
74 75
75/* minimum Lua stack available to a C function */ 76/* minimum Lua stack available to a C function */
@@ -104,7 +105,6 @@ typedef LUA_NUMBER lua_Number;
104LUA_API lua_State *lua_open (void); 105LUA_API lua_State *lua_open (void);
105LUA_API void lua_close (lua_State *L); 106LUA_API void lua_close (lua_State *L);
106LUA_API lua_State *lua_newthread (lua_State *L); 107LUA_API lua_State *lua_newthread (lua_State *L);
107LUA_API void lua_closethread (lua_State *L, lua_State *t);
108 108
109LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf); 109LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
110 110
@@ -142,6 +142,7 @@ LUA_API const char *lua_tostring (lua_State *L, int idx);
142LUA_API size_t lua_strlen (lua_State *L, int idx); 142LUA_API size_t lua_strlen (lua_State *L, int idx);
143LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); 143LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx);
144LUA_API void *lua_touserdata (lua_State *L, int idx); 144LUA_API void *lua_touserdata (lua_State *L, int idx);
145LUA_API lua_State *lua_tothread (lua_State *L, int idx);
145LUA_API const void *lua_topointer (lua_State *L, int idx); 146LUA_API const void *lua_topointer (lua_State *L, int idx);
146 147
147 148
diff --git a/lvm.c b/lvm.c
index 68e6a080..8b72ae92 100644
--- a/lvm.c
+++ b/lvm.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lvm.c,v 1.256 2002/09/19 20:12:47 roberto Exp roberto $ 2** $Id: lvm.c,v 1.257 2002/10/08 18:46:08 roberto Exp roberto $
3** Lua virtual machine 3** Lua virtual machine
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -263,22 +263,23 @@ int luaV_equalval (lua_State *L, const TObject *t1, const TObject *t2) {
263 switch (ttype(t1)) { 263 switch (ttype(t1)) {
264 case LUA_TNIL: return 1; 264 case LUA_TNIL: return 1;
265 case LUA_TNUMBER: return nvalue(t1) == nvalue(t2); 265 case LUA_TNUMBER: return nvalue(t1) == nvalue(t2);
266 case LUA_TSTRING: return tsvalue(t1) == tsvalue(t2);
267 case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */ 266 case LUA_TBOOLEAN: return bvalue(t1) == bvalue(t2); /* true must be 1 !! */
268 case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2); 267 case LUA_TLIGHTUSERDATA: return pvalue(t1) == pvalue(t2);
269 case LUA_TFUNCTION: return clvalue(t1) == clvalue(t2); 268 case LUA_TUSERDATA: {
270 case LUA_TUSERDATA:
271 if (uvalue(t1) == uvalue(t2)) return 1; 269 if (uvalue(t1) == uvalue(t2)) return 1;
272 else if ((tm = fasttm(L, uvalue(t1)->uv.metatable, TM_EQ)) == NULL && 270 else if ((tm = fasttm(L, uvalue(t1)->uv.metatable, TM_EQ)) == NULL &&
273 (tm = fasttm(L, uvalue(t2)->uv.metatable, TM_EQ)) == NULL) 271 (tm = fasttm(L, uvalue(t2)->uv.metatable, TM_EQ)) == NULL)
274 return 0; /* no TM */ 272 return 0; /* no TM */
275 else break; /* will try TM */ 273 else break; /* will try TM */
276 case LUA_TTABLE: 274 }
275 case LUA_TTABLE: {
277 if (hvalue(t1) == hvalue(t2)) return 1; 276 if (hvalue(t1) == hvalue(t2)) return 1;
278 else if ((tm = fasttm(L, hvalue(t1)->metatable, TM_EQ)) == NULL && 277 else if ((tm = fasttm(L, hvalue(t1)->metatable, TM_EQ)) == NULL &&
279 (tm = fasttm(L, hvalue(t2)->metatable, TM_EQ)) == NULL) 278 (tm = fasttm(L, hvalue(t2)->metatable, TM_EQ)) == NULL)
280 return 0; /* no TM */ 279 return 0; /* no TM */
281 else break; /* will try TM */ 280 else break; /* will try TM */
281 }
282 default: return gcvalue(t1) == gcvalue(t2);
282 } 283 }
283 callTMres(L, tm, t1, t2); /* call TM */ 284 callTMres(L, tm, t1, t2); /* call TM */
284 return !l_isfalse(L->top); 285 return !l_isfalse(L->top);