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