Home | History | Annotate | Download | only in src
      1 /*
      2 ** $Id: lcorolib.c,v 1.5 2013/02/21 13:44:53 roberto Exp $
      3 ** Coroutine Library
      4 ** See Copyright Notice in lua.h
      5 */
      6 
      7 
      8 #include <stdlib.h>
      9 
     10 
     11 #define lcorolib_c
     12 #define LUA_LIB
     13 
     14 #include "lua.h"
     15 
     16 #include "lauxlib.h"
     17 #include "lualib.h"
     18 
     19 
     20 static int auxresume (lua_State *L, lua_State *co, int narg) {
     21   int status;
     22   if (!lua_checkstack(co, narg)) {
     23     lua_pushliteral(L, "too many arguments to resume");
     24     return -1;  /* error flag */
     25   }
     26   if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
     27     lua_pushliteral(L, "cannot resume dead coroutine");
     28     return -1;  /* error flag */
     29   }
     30   lua_xmove(L, co, narg);
     31   status = lua_resume(co, L, narg);
     32   if (status == LUA_OK || status == LUA_YIELD) {
     33     int nres = lua_gettop(co);
     34     if (!lua_checkstack(L, nres + 1)) {
     35       lua_pop(co, nres);  /* remove results anyway */
     36       lua_pushliteral(L, "too many results to resume");
     37       return -1;  /* error flag */
     38     }
     39     lua_xmove(co, L, nres);  /* move yielded values */
     40     return nres;
     41   }
     42   else {
     43     lua_xmove(co, L, 1);  /* move error message */
     44     return -1;  /* error flag */
     45   }
     46 }
     47 
     48 
     49 static int luaB_coresume (lua_State *L) {
     50   lua_State *co = lua_tothread(L, 1);
     51   int r;
     52   luaL_argcheck(L, co, 1, "coroutine expected");
     53   r = auxresume(L, co, lua_gettop(L) - 1);
     54   if (r < 0) {
     55     lua_pushboolean(L, 0);
     56     lua_insert(L, -2);
     57     return 2;  /* return false + error message */
     58   }
     59   else {
     60     lua_pushboolean(L, 1);
     61     lua_insert(L, -(r + 1));
     62     return r + 1;  /* return true + `resume' returns */
     63   }
     64 }
     65 
     66 
     67 static int luaB_auxwrap (lua_State *L) {
     68   lua_State *co = lua_tothread(L, lua_upvalueindex(1));
     69   int r = auxresume(L, co, lua_gettop(L));
     70   if (r < 0) {
     71     if (lua_isstring(L, -1)) {  /* error object is a string? */
     72       luaL_where(L, 1);  /* add extra info */
     73       lua_insert(L, -2);
     74       lua_concat(L, 2);
     75     }
     76     return lua_error(L);  /* propagate error */
     77   }
     78   return r;
     79 }
     80 
     81 
     82 static int luaB_cocreate (lua_State *L) {
     83   lua_State *NL;
     84   luaL_checktype(L, 1, LUA_TFUNCTION);
     85   NL = lua_newthread(L);
     86   lua_pushvalue(L, 1);  /* move function to top */
     87   lua_xmove(L, NL, 1);  /* move function from L to NL */
     88   return 1;
     89 }
     90 
     91 
     92 static int luaB_cowrap (lua_State *L) {
     93   luaB_cocreate(L);
     94   lua_pushcclosure(L, luaB_auxwrap, 1);
     95   return 1;
     96 }
     97 
     98 
     99 static int luaB_yield (lua_State *L) {
    100   return lua_yield(L, lua_gettop(L));
    101 }
    102 
    103 
    104 static int luaB_costatus (lua_State *L) {
    105   lua_State *co = lua_tothread(L, 1);
    106   luaL_argcheck(L, co, 1, "coroutine expected");
    107   if (L == co) lua_pushliteral(L, "running");
    108   else {
    109     switch (lua_status(co)) {
    110       case LUA_YIELD:
    111         lua_pushliteral(L, "suspended");
    112         break;
    113       case LUA_OK: {
    114         lua_Debug ar;
    115         if (lua_getstack(co, 0, &ar) > 0)  /* does it have frames? */
    116           lua_pushliteral(L, "normal");  /* it is running */
    117         else if (lua_gettop(co) == 0)
    118             lua_pushliteral(L, "dead");
    119         else
    120           lua_pushliteral(L, "suspended");  /* initial state */
    121         break;
    122       }
    123       default:  /* some error occurred */
    124         lua_pushliteral(L, "dead");
    125         break;
    126     }
    127   }
    128   return 1;
    129 }
    130 
    131 
    132 static int luaB_corunning (lua_State *L) {
    133   int ismain = lua_pushthread(L);
    134   lua_pushboolean(L, ismain);
    135   return 2;
    136 }
    137 
    138 
    139 static const luaL_Reg co_funcs[] = {
    140   {"create", luaB_cocreate},
    141   {"resume", luaB_coresume},
    142   {"running", luaB_corunning},
    143   {"status", luaB_costatus},
    144   {"wrap", luaB_cowrap},
    145   {"yield", luaB_yield},
    146   {NULL, NULL}
    147 };
    148 
    149 
    150 
    151 LUAMOD_API int luaopen_coroutine (lua_State *L) {
    152   luaL_newlib(L, co_funcs);
    153   return 1;
    154 }
    155 
    156