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