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