浏览代码

cleaner API for coroutines

Roberto Ierusalimschy 21 年之前
父节点
当前提交
2419f2bf02
共有 7 个文件被更改,包括 79 次插入39 次删除
  1. 17 2
      lapi.c
  2. 33 7
      lbaselib.c
  3. 14 18
      ldo.c
  4. 2 2
      lstate.c
  5. 2 2
      lstate.h
  6. 9 6
      lua.h
  7. 2 2
      lvm.c

+ 17 - 2
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
 */

+ 33 - 7
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}
 };
 

+ 14 - 18
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;
 }

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

+ 2 - 2
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;

+ 9 - 6
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:[email protected]
@@ -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

+ 2 - 2
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;
       }