• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 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 
auxresume(lua_State * L,lua_State * co,int narg)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 
luaB_coresume(lua_State * L)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 
luaB_auxwrap(lua_State * L)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 
luaB_cocreate(lua_State * L)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 
luaB_cowrap(lua_State * L)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 
luaB_yield(lua_State * L)99 static int luaB_yield (lua_State *L) {
100   return lua_yield(L, lua_gettop(L));
101 }
102 
103 
luaB_costatus(lua_State * L)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 
luaB_corunning(lua_State * L)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 
luaopen_coroutine(lua_State * L)151 LUAMOD_API int luaopen_coroutine (lua_State *L) {
152   luaL_newlib(L, co_funcs);
153   return 1;
154 }
155 
156