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