diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-10-25 17:05:28 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-10-25 17:05:28 -0300 |
commit | 96e15b8501e5d8fc40c475cbac573f910ab5853b (patch) | |
tree | 2c8efededa6849704f0db3075d0cbe0efaa40b2d | |
parent | 0fd91b1b087b478fffa36f96bc0f608d86627a4b (diff) | |
download | lua-96e15b8501e5d8fc40c475cbac573f910ab5853b.tar.gz lua-96e15b8501e5d8fc40c475cbac573f910ab5853b.tar.bz2 lua-96e15b8501e5d8fc40c475cbac573f910ab5853b.zip |
threads now are real Lua objects, subject to garbage collection
-rw-r--r-- | lapi.c | 20 | ||||
-rw-r--r-- | lbaselib.c | 76 | ||||
-rw-r--r-- | ldo.c | 26 | ||||
-rw-r--r-- | lgc.c | 89 | ||||
-rw-r--r-- | lobject.h | 67 | ||||
-rw-r--r-- | lstate.c | 103 | ||||
-rw-r--r-- | lstate.h | 31 | ||||
-rw-r--r-- | ltests.c | 7 | ||||
-rw-r--r-- | ltests.h | 11 | ||||
-rw-r--r-- | ltm.c | 4 | ||||
-rw-r--r-- | lua.h | 5 | ||||
-rw-r--r-- | lvm.c | 11 |
12 files changed, 246 insertions, 204 deletions
@@ -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 | ||
118 | LUA_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 | ||
337 | LUA_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 | |||
325 | LUA_API const void *lua_topointer (lua_State *L, int index) { | 343 | LUA_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; |
@@ -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 | ||
538 | static int luaB_resume (lua_State *L) { | 541 | static 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 | ||
549 | static 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 | ||
550 | static int gc_coroutine (lua_State *L) { | 567 | static 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 | ||
557 | static int luaB_coroutine (lua_State *L) { | 574 | static 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); | 594 | static 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 | ||
587 | static const luaL_reg co_funcs[] = { | 605 | static 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 | |||
594 | static 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 | ||
626 | LUALIB_API int lua_baselibopen (lua_State *L) { | 634 | LUALIB_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; |
@@ -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; |
@@ -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 | ||
102 | static 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 | |||
112 | static 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 | |||
102 | static void reallymarkobject (GCState *st, GCObject *o) { | 128 | static 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 | |||
122 | static 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 | |||
132 | static 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 */ | ||
389 | static 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 | |||
392 | static void mark (lua_State *L) { | 399 | static 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; |
@@ -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 | */ | ||
29 | typedef union GCObject GCObject; | ||
30 | |||
31 | |||
32 | /* | ||
27 | ** Common header for all collectable objects | 33 | ** Common header for all collectable objects |
28 | */ | 34 | */ |
29 | typedef struct GCheader { | 35 | typedef 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 | */ |
41 | typedef union { | 52 | typedef 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 */ | |||
142 | typedef union TString { | 160 | typedef 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 { | |||
160 | typedef union Udata { | 176 | typedef 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 | */ |
177 | typedef struct Proto { | 191 | typedef 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 | ||
212 | typedef struct UpVal { | 224 | typedef 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 | ||
225 | typedef struct CClosure { | 235 | typedef 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 | ||
236 | typedef struct LClosure { | 244 | typedef 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 | ||
269 | typedef struct Table { | 275 | typedef 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 | */ | ||
304 | typedef 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 | ||
315 | extern const TObject luaO_nilobject; | 306 | extern const TObject luaO_nilobject; |
316 | 307 | ||
@@ -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 | ||
28 | union UEXTRASPACE {L_Umaxalign a; LUA_USERSTATE b;}; | ||
29 | #define EXTRASPACE (sizeof(UEXTRASPACE)) | ||
30 | #endif | ||
22 | 31 | ||
23 | 32 | ||
24 | static void close_state (lua_State *L); | 33 | static void close_state (lua_State *L); |
25 | 34 | ||
26 | 35 | ||
36 | static 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 | ||
37 | static void stack_init (lua_State *L, lua_State *OL) { | 56 | static 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 | ||
106 | LUA_API lua_State *lua_newthread (lua_State *OL) { | 126 | lua_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 | ||
124 | LUA_API lua_State *lua_open (void) { | 137 | LUA_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 | ||
142 | void luaE_closethread (lua_State *OL, lua_State *L) { | 153 | void 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 | |||
167 | LUA_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 | ||
175 | LUA_API void lua_close (lua_State *L) { | 177 | LUA_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 | ||
@@ -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 | */ |
135 | struct lua_State { | 130 | struct 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 | ||
161 | void luaE_closethread (lua_State *OL, lua_State *L); | 154 | /* |
155 | ** Union of all collectable objects | ||
156 | */ | ||
157 | union 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 | |||
169 | lua_State *luaE_newthread (lua_State *L); | ||
170 | void luaE_freethread (lua_State *L, lua_State *L1); | ||
162 | 171 | ||
163 | #endif | 172 | #endif |
164 | 173 | ||
@@ -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) { | |||
423 | static int newstate (lua_State *L) { | 422 | static 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 | ||
726 | int luaB_opentests (lua_State *L) { | 725 | int 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); |
@@ -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 */ |
44 | extern int islocked; | 44 | extern 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 | ||
51 | int luaB_opentests (lua_State *L); | 52 | int luaB_opentests (lua_State *L); |
@@ -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 | ||
20 | const char *const luaT_typenames[] = { | 20 | const 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 | ||
@@ -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; | |||
104 | LUA_API lua_State *lua_open (void); | 105 | LUA_API lua_State *lua_open (void); |
105 | LUA_API void lua_close (lua_State *L); | 106 | LUA_API void lua_close (lua_State *L); |
106 | LUA_API lua_State *lua_newthread (lua_State *L); | 107 | LUA_API lua_State *lua_newthread (lua_State *L); |
107 | LUA_API void lua_closethread (lua_State *L, lua_State *t); | ||
108 | 108 | ||
109 | LUA_API lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf); | 109 | LUA_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); | |||
142 | LUA_API size_t lua_strlen (lua_State *L, int idx); | 142 | LUA_API size_t lua_strlen (lua_State *L, int idx); |
143 | LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); | 143 | LUA_API lua_CFunction lua_tocfunction (lua_State *L, int idx); |
144 | LUA_API void *lua_touserdata (lua_State *L, int idx); | 144 | LUA_API void *lua_touserdata (lua_State *L, int idx); |
145 | LUA_API lua_State *lua_tothread (lua_State *L, int idx); | ||
145 | LUA_API const void *lua_topointer (lua_State *L, int idx); | 146 | LUA_API const void *lua_topointer (lua_State *L, int idx); |
146 | 147 | ||
147 | 148 | ||
@@ -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); |