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 19static 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 48static 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 66static 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 81static 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 91static int luaB_cowrap (lua_State *L) { 92 luaB_cocreate(L); 93 lua_pushcclosure(L, luaB_auxwrap, 1); 94 return 1; 95} 96 97 98static int luaB_yield (lua_State *L) { 99 return lua_yield(L, lua_gettop(L)); 100} 101 102 103static 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 131static int luaB_corunning (lua_State *L) { 132 int ismain = lua_pushthread(L); 133 lua_pushboolean(L, ismain); 134 return 2; 135} 136 137 138static 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 150LUAMOD_API int luaopen_coroutine (lua_State *L) { 151 luaL_newlib(L, co_funcs); 152 return 1; 153} 154 155