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