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); |
