lua

A copy of the Lua development repository
Log | Files | Refs | README

commit 2419f2bf02a9165471248f09bae57e3fa134e545
parent 0e54d2be365ec77cb455e0d0f3c5c6f9efa6e04c
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Wed, 15 Sep 2004 17:39:20 -0300

cleaner API for coroutines

Diffstat:
Mlapi.c | 19+++++++++++++++++--
Mlbaselib.c | 40+++++++++++++++++++++++++++++++++-------
Mldo.c | 32++++++++++++++------------------
Mlstate.c | 4++--
Mlstate.h | 4++--
Mlua.h | 15+++++++++------
Mlvm.c | 4++--
7 files changed, 79 insertions(+), 39 deletions(-)

diff --git a/lapi.c b/lapi.c @@ -1,5 +1,5 @@ /* -** $Id: lapi.c,v 2.17 2004/08/17 17:45:45 roberto Exp roberto $ +** $Id: lapi.c,v 2.18 2004/08/30 13:44:44 roberto Exp roberto $ ** Lua API ** See Copyright Notice in lua.h */ @@ -97,6 +97,7 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) { if (from == to) return; lua_lock(to); api_checknelems(from, n); + api_check(L, G(from) == G(to)); from->top -= n; for (i = 0; i < n; i++) { setobj2s(to, to->top, from->top + i); @@ -479,6 +480,15 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { } +LUA_API int lua_pushthread (lua_State *L) { + lua_lock(L); + setthvalue(L, L->top, L); + api_incr_top(L); + lua_unlock(L); + return (G(L)->mainthread == L); +} + + /* ** get functions (Lua -> stack) @@ -650,7 +660,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) { case LUA_TTABLE: { hvalue(obj)->metatable = mt; if (mt) - luaC_objbarrier(L, hvalue(obj), mt); + luaC_objbarriert(L, hvalue(obj), mt); break; } case LUA_TUSERDATA: { @@ -816,6 +826,11 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data) { } +LUA_API int lua_threadstatus (lua_State *L) { + return L->status; +} + + /* ** Garbage-collection function */ diff --git a/lbaselib.c b/lbaselib.c @@ -1,5 +1,5 @@ /* -** $Id: lbaselib.c,v 1.156 2004/08/30 18:35:14 roberto Exp roberto $ +** $Id: lbaselib.c,v 1.157 2004/09/03 13:16:48 roberto Exp roberto $ ** Basic library ** See Copyright Notice in lua.h */ @@ -523,9 +523,13 @@ static int auxresume (lua_State *L, lua_State *co, int narg) { int status; if (!lua_checkstack(co, narg)) luaL_error(L, "too many arguments to resume"); + if (lua_threadstatus(co) == 0 && lua_gettop(co) == 0) { + lua_pushliteral(L, "cannot resume dead coroutine"); + return -1; /* error flag */ + } lua_xmove(L, co, narg); status = lua_resume(co, narg); - if (status == 0) { + if (status == 0 || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres)) luaL_error(L, "too many results to resume"); @@ -599,22 +603,44 @@ static int luaB_costatus (lua_State *L) { luaL_argcheck(L, co, 1, "coroutine expected"); if (L == co) lua_pushliteral(L, "running"); else { - lua_Debug ar; - if (lua_getstack(co, 0, &ar) == 0 && lua_gettop(co) == 0) - lua_pushliteral(L, "dead"); - else - lua_pushliteral(L, "suspended"); + switch (lua_threadstatus(co)) { + case LUA_YIELD: + lua_pushliteral(L, "suspended"); + break; + case 0: { + lua_Debug ar; + if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */ + lua_pushliteral(L, "normal"); /* it is running */ + else if (lua_gettop(co) == 0) + lua_pushliteral(L, "dead"); + else + lua_pushliteral(L, "suspended"); /* initial state */ + break; + } + default: /* some error occured */ + lua_pushliteral(L, "dead"); + break; + } } return 1; } +static int luaB_cocurrent (lua_State *L) { + if (lua_pushthread(L)) + return 0; /* main thread is not a coroutine */ + else + return 1; +} + + static const luaL_reg co_funcs[] = { {"create", luaB_cocreate}, {"wrap", luaB_cowrap}, {"resume", luaB_coresume}, {"yield", luaB_yield}, {"status", luaB_costatus}, + {"current", luaB_cocurrent}, {NULL, NULL} }; diff --git a/ldo.c b/ldo.c @@ -1,5 +1,5 @@ /* -** $Id: ldo.c,v 2.8 2004/09/03 15:48:56 roberto Exp roberto $ +** $Id: ldo.c,v 2.9 2004/09/08 14:23:09 roberto Exp roberto $ ** Stack and Call structure of Lua ** See Copyright Notice in lua.h */ @@ -358,7 +358,7 @@ static void resume (lua_State *L, void *ud) { StkId firstResult; int nargs = *cast(int *, ud); CallInfo *ci = L->ci; - if (!L->isSuspended) { + if (L->status != LUA_YIELD) { lua_assert(ci == L->base_ci && nargs < L->top - L->base); luaD_precall(L, L->top - (nargs + 1), LUA_MULTRET); /* start coroutine */ } @@ -372,10 +372,11 @@ static void resume (lua_State *L, void *ud) { if (nresults >= 0) L->top = L->ci->top; } /* else yielded inside a hook: just continue its execution */ } - L->isSuspended = 0; + L->status = 0; firstResult = luaV_execute(L, L->ci - L->base_ci); - if (firstResult != NULL) /* return? */ + if (firstResult != NULL) { /* return? */ luaD_poscall(L, LUA_MULTRET, firstResult); /* finalize this coroutine */ + } } @@ -393,25 +394,20 @@ LUA_API int lua_resume (lua_State *L, int nargs) { lu_byte old_allowhooks; lua_lock(L); lua_assert(L->errfunc == 0 && L->nCcalls == 0); - if (!L->isSuspended) { - if (L->ci == L->base_ci) { /* no activation record? */ - if (nargs >= L->top - L->base) - return resume_error(L, "cannot resume dead coroutine"); - } - else + if (L->status != LUA_YIELD) { + if (L->status != 0) + return resume_error(L, "cannot resume dead coroutine"); + else if (L->ci != L->base_ci) return resume_error(L, "cannot resume non-suspended coroutine"); } old_allowhooks = L->allowhook; status = luaD_rawrunprotected(L, resume, &nargs); if (status != 0) { /* error? */ - L->ci = L->base_ci; /* go back to initial level */ - L->base = L->ci->base; - L->nCcalls = 0; - luaF_close(L, L->base); /* close eventual pending closures */ - seterrorobj(L, status, L->base); - L->allowhook = old_allowhooks; - restore_stack_limit(L); + L->status = status; /* mark thread as `dead' */ + seterrorobj(L, status, L->top); } + else + status = L->status; lua_unlock(L); return status; } @@ -431,7 +427,7 @@ LUA_API int lua_yield (lua_State *L, int nresults) { L->top = L->base + nresults; } } /* else it's an yield inside a hook: nothing to do */ - L->isSuspended = 1; + L->status = LUA_YIELD; lua_unlock(L); return -1; } diff --git a/lstate.c b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.12 2004/08/30 13:44:44 roberto Exp $ +** $Id: lstate.c,v 2.13 2004/09/08 14:23:09 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -114,7 +114,7 @@ static void preinit_state (lua_State *L, global_State *g) { L->openupval = NULL; L->size_ci = 0; L->nCcalls = 0; - L->isSuspended = 0; + L->status = 0; L->base_ci = L->ci = NULL; L->errfunc = 0; setnilvalue(gt(L)); diff --git a/lstate.h b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.6 2004/08/24 20:12:06 roberto Exp roberto $ +** $Id: lstate.h,v 2.7 2004/08/30 13:44:44 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -111,7 +111,7 @@ struct lua_State { unsigned short nCcalls; /* number of nested C calls */ lu_byte hookmask; lu_byte allowhook; - lu_byte isSuspended; + lu_byte status; int basehookcount; int hookcount; lua_Hook hook; diff --git a/lua.h b/lua.h @@ -1,5 +1,5 @@ /* -** $Id: lua.h,v 1.191 2004/06/02 17:37:03 roberto Exp roberto $ +** $Id: lua.h,v 1.192 2004/06/04 15:30:53 roberto Exp roberto $ ** Lua - An Extensible Extension Language ** Tecgraf: Computer Graphics Technology Group, PUC-Rio, Brazil ** http://www.lua.org mailto:info@lua.org @@ -37,11 +37,12 @@ #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) -/* error codes for `lua_pcall' */ -#define LUA_ERRRUN 1 -#define LUA_ERRSYNTAX 2 -#define LUA_ERRMEM 3 -#define LUA_ERRERR 4 +/* return codes for `lua_pcall', `lua_resume', and `lua_threadstatus' */ +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 typedef struct lua_State lua_State; @@ -165,6 +166,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...); LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); LUA_API void lua_pushboolean (lua_State *L, int b); LUA_API void lua_pushlightuserdata (lua_State *L, void *p); +LUA_API int lua_pushthread (lua_State *L); /* @@ -208,6 +210,7 @@ LUA_API int lua_dump (lua_State *L, lua_Chunkwriter writer, void *data); */ LUA_API int lua_yield (lua_State *L, int nresults); LUA_API int lua_resume (lua_State *L, int narg); +LUA_API int lua_threadstatus (lua_State *L); /* ** garbage-collection function and options diff --git a/lvm.c b/lvm.c @@ -1,5 +1,5 @@ /* -** $Id: lvm.c,v 2.12 2004/08/10 19:17:23 roberto Exp roberto $ +** $Id: lvm.c,v 2.13 2004/08/12 14:19:51 roberto Exp roberto $ ** Lua virtual machine ** See Copyright Notice in lua.h */ @@ -398,7 +398,7 @@ StkId luaV_execute (lua_State *L, int nexeccalls) { if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { traceexec(L, pc); /***/ - if (L->isSuspended) { /* did hook yield? */ + if (L->status == LUA_YIELD) { /* did hook yield? */ L->ci->savedpc = pc - 1; return NULL; }