lua

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

lcorolib.c (4877B)


      1 /*
      2 ** $Id: lcorolib.c $
      3 ** Coroutine Library
      4 ** See Copyright Notice in lua.h
      5 */
      6 
      7 #define lcorolib_c
      8 #define LUA_LIB
      9 
     10 #include "lprefix.h"
     11 
     12 
     13 #include <stdlib.h>
     14 
     15 #include "lua.h"
     16 
     17 #include "lauxlib.h"
     18 #include "lualib.h"
     19 #include "llimits.h"
     20 
     21 
     22 static lua_State *getco (lua_State *L) {
     23   lua_State *co = lua_tothread(L, 1);
     24   luaL_argexpected(L, co, 1, "thread");
     25   return co;
     26 }
     27 
     28 
     29 /*
     30 ** Resumes a coroutine. Returns the number of results for non-error
     31 ** cases or -1 for errors.
     32 */
     33 static int auxresume (lua_State *L, lua_State *co, int narg) {
     34   int status, nres;
     35   if (l_unlikely(!lua_checkstack(co, narg))) {
     36     lua_pushliteral(L, "too many arguments to resume");
     37     return -1;  /* error flag */
     38   }
     39   lua_xmove(L, co, narg);
     40   status = lua_resume(co, L, narg, &nres);
     41   if (l_likely(status == LUA_OK || status == LUA_YIELD)) {
     42     if (l_unlikely(!lua_checkstack(L, nres + 1))) {
     43       lua_pop(co, nres);  /* remove results anyway */
     44       lua_pushliteral(L, "too many results to resume");
     45       return -1;  /* error flag */
     46     }
     47     lua_xmove(co, L, nres);  /* move yielded values */
     48     return nres;
     49   }
     50   else {
     51     lua_xmove(co, L, 1);  /* move error message */
     52     return -1;  /* error flag */
     53   }
     54 }
     55 
     56 
     57 static int luaB_coresume (lua_State *L) {
     58   lua_State *co = getco(L);
     59   int r;
     60   r = auxresume(L, co, lua_gettop(L) - 1);
     61   if (l_unlikely(r < 0)) {
     62     lua_pushboolean(L, 0);
     63     lua_insert(L, -2);
     64     return 2;  /* return false + error message */
     65   }
     66   else {
     67     lua_pushboolean(L, 1);
     68     lua_insert(L, -(r + 1));
     69     return r + 1;  /* return true + 'resume' returns */
     70   }
     71 }
     72 
     73 
     74 static int luaB_auxwrap (lua_State *L) {
     75   lua_State *co = lua_tothread(L, lua_upvalueindex(1));
     76   int r = auxresume(L, co, lua_gettop(L));
     77   if (l_unlikely(r < 0)) {  /* error? */
     78     int stat = lua_status(co);
     79     if (stat != LUA_OK && stat != LUA_YIELD) {  /* error in the coroutine? */
     80       stat = lua_closethread(co, L);  /* close its tbc variables */
     81       lua_assert(stat != LUA_OK);
     82       lua_xmove(co, L, 1);  /* move error message to the caller */
     83     }
     84     if (stat != LUA_ERRMEM &&  /* not a memory error and ... */
     85         lua_type(L, -1) == LUA_TSTRING) {  /* ... error object is a string? */
     86       luaL_where(L, 1);  /* add extra info, if available */
     87       lua_insert(L, -2);
     88       lua_concat(L, 2);
     89     }
     90     return lua_error(L);  /* propagate error */
     91   }
     92   return r;
     93 }
     94 
     95 
     96 static int luaB_cocreate (lua_State *L) {
     97   lua_State *NL;
     98   luaL_checktype(L, 1, LUA_TFUNCTION);
     99   NL = lua_newthread(L);
    100   lua_pushvalue(L, 1);  /* move function to top */
    101   lua_xmove(L, NL, 1);  /* move function from L to NL */
    102   return 1;
    103 }
    104 
    105 
    106 static int luaB_cowrap (lua_State *L) {
    107   luaB_cocreate(L);
    108   lua_pushcclosure(L, luaB_auxwrap, 1);
    109   return 1;
    110 }
    111 
    112 
    113 static int luaB_yield (lua_State *L) {
    114   return lua_yield(L, lua_gettop(L));
    115 }
    116 
    117 
    118 #define COS_RUN		0
    119 #define COS_DEAD	1
    120 #define COS_YIELD	2
    121 #define COS_NORM	3
    122 
    123 
    124 static const char *const statname[] =
    125   {"running", "dead", "suspended", "normal"};
    126 
    127 
    128 static int auxstatus (lua_State *L, lua_State *co) {
    129   if (L == co) return COS_RUN;
    130   else {
    131     switch (lua_status(co)) {
    132       case LUA_YIELD:
    133         return COS_YIELD;
    134       case LUA_OK: {
    135         lua_Debug ar;
    136         if (lua_getstack(co, 0, &ar))  /* does it have frames? */
    137           return COS_NORM;  /* it is running */
    138         else if (lua_gettop(co) == 0)
    139             return COS_DEAD;
    140         else
    141           return COS_YIELD;  /* initial state */
    142       }
    143       default:  /* some error occurred */
    144         return COS_DEAD;
    145     }
    146   }
    147 }
    148 
    149 
    150 static int luaB_costatus (lua_State *L) {
    151   lua_State *co = getco(L);
    152   lua_pushstring(L, statname[auxstatus(L, co)]);
    153   return 1;
    154 }
    155 
    156 
    157 static int luaB_yieldable (lua_State *L) {
    158   lua_State *co = lua_isnone(L, 1) ? L : getco(L);
    159   lua_pushboolean(L, lua_isyieldable(co));
    160   return 1;
    161 }
    162 
    163 
    164 static int luaB_corunning (lua_State *L) {
    165   int ismain = lua_pushthread(L);
    166   lua_pushboolean(L, ismain);
    167   return 2;
    168 }
    169 
    170 
    171 static int luaB_close (lua_State *L) {
    172   lua_State *co = getco(L);
    173   int status = auxstatus(L, co);
    174   switch (status) {
    175     case COS_DEAD: case COS_YIELD: {
    176       status = lua_closethread(co, L);
    177       if (status == LUA_OK) {
    178         lua_pushboolean(L, 1);
    179         return 1;
    180       }
    181       else {
    182         lua_pushboolean(L, 0);
    183         lua_xmove(co, L, 1);  /* move error message */
    184         return 2;
    185       }
    186     }
    187     default:  /* normal or running coroutine */
    188       return luaL_error(L, "cannot close a %s coroutine", statname[status]);
    189   }
    190 }
    191 
    192 
    193 static const luaL_Reg co_funcs[] = {
    194   {"create", luaB_cocreate},
    195   {"resume", luaB_coresume},
    196   {"running", luaB_corunning},
    197   {"status", luaB_costatus},
    198   {"wrap", luaB_cowrap},
    199   {"yield", luaB_yield},
    200   {"isyieldable", luaB_yieldable},
    201   {"close", luaB_close},
    202   {NULL, NULL}
    203 };
    204 
    205 
    206 
    207 LUAMOD_API int luaopen_coroutine (lua_State *L) {
    208   luaL_newlib(L, co_funcs);
    209   return 1;
    210 }
    211