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