// [-3, +3, e] static int lcf_socket_read(lua_State *L) { as_lm_socket_t *sock = (as_lm_socket_t *)luaL_checkudata( L, 1, LM_SOCKET); int timeout = luaL_checkinteger(L, 3); if (timeout < 0) { timeout = LAS_D_TIMOUT_SECS; } as_thread_res_t *res = sock->res; if (res == NULL) { lua_pushinteger(L, 0); lua_pushnil(L); lua_pushinteger(L, EBADFD); return 3; } if (res->th->mode != AS_TMODE_SIMPLE) { lua_pushstring(L, "ev error"); lua_error(L); } lua_pushinteger(L, LAS_S_YIELD_FOR_IO); lua_pushlightuserdata(L, res); lua_pushinteger(L, LAS_S_WAIT_FOR_INPUT); lua_pushinteger(L, timeout); return lua_yieldk(L, 4, (lua_KContext)NULL, k_socket_read); }
int32_t context_lua_t::lua_yield_send(lua_State *L, uint32_t destination, yiled_finalize_t fnz, void* fnz_ud, lua_KFunction yieldk, int64_t timeout) { int stacks; context_lua_t* lctx = context_lua_t::lua_get_context(L); lctx->m_shared->m_yielding_destination = destination; lctx->m_shared->m_yielding_depth = 1; lctx->m_shared->m_yielding_finalize = fnz; /* fnz should not be null better */ lctx->m_shared->m_yielding_finalize_userdata = fnz_ud; lctx->m_shared->m_yielding_status = UV_OK; lctx->m_shared->m_yielding_timeout = timeout; if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ return lua_yieldk(L, 0, 0, yieldk); /* n(0) result to yield and ctx(0) is not allowed */ } else { if (stacks) { /* stack enough, but not yield-able */ lctx->yielding_finalize(NULL, NL_EYIELD); lua_pushboolean(L, 0); lua_pushinteger(L, NL_EYIELD); lua_pushnil(L); lua_pushnil(L); return (yieldk == NULL) ? 4 : yieldk(L, LUA_YIELD, 0); } else { /* error jump directly */ lctx->yielding_finalize(NULL, NL_ESTACKLESS); return luaL_error(L, "attempt to yield across a stack-less coroutine"); } } }
// startTalking() // startTalking opens the conversation screen and returns its interface. int talk_lua_start(lua_State *L) { lua_getfield(L, LUA_REGISTRYINDEX, "game/stateStack"); if (lua_isnil(L, -1)) { return luaL_error(L, "game not initialized yet"); } state_stack *stack = (state_stack*) lua_touserdata(L, -1); lua_pop(L, 1); state_desc *top = (state_desc*) table_ind(stack, stack->m_len-1); int i; if (lua_getctx(L, &i) == LUA_OK) { top->m_fnPushChild = _talk_push; top->m_pChildData = (void*) L; return lua_yieldk(L, 0, 0, talk_lua_start); } luaL_Reg funcs[] = { { "resetChoices", _lua_resetchoices }, { "addChoice", _lua_addchoice }, { "offerChoice", _lua_offerchoice }, { "wait", _lua_wait }, { "say", _lua_say }, { "stop", _lua_stop }, { nullptr, nullptr }, }; luaL_newlibtable(L, funcs); top = (state_desc*) table_ind(stack, stack->m_len-1); lua_pushlightuserdata(L, top->m_pData); luaL_setfuncs(L, funcs, 1); return 1; }
// [-0, +3, e] static int lcf_socket_ev_wait(lua_State *L) { int timeout = luaL_checkinteger(L, 1); lua_pushinteger(L, LAS_S_YIELD_FOR_EV); lua_pushinteger(L, timeout); return lua_yieldk(L, 2, (lua_KContext)NULL, k_socket_ev_wait); }
static int k_socket_send(lua_State *L, int status, lua_KContext c) { as_thread_res_t *res = NULL; _send_ctx_t *ctx = (_send_ctx_t *)c; if (status == LUA_OK) { res = ctx->res; } else if (status == LUA_YIELD) { int type = luaL_checkinteger(L, 1); // as_thread_res_t *rres = (as_thread_res_t *)lua_touserdata(L, 2); // int io = luaL_checkinteger(L, 3); if (type == LAS_S_RESUME_IO_TIMEOUT) { lua_pushinteger(L, ctx->idx); lua_pushinteger(L, ETIMEDOUT); memp_recycle(ctx); return 2; } else { res = (as_thread_res_t *)lua_touserdata(L, -2); lua_pop(L, 3); } } else { memp_recycle(ctx); lua_pushstring(L, "send error"); lua_error(L); } int fd = res->fdf(res); while (1) { const char *buf = ctx->buf + ctx->idx; size_t len = ctx->len - ctx->idx; ssize_t nbyte = send(fd, buf, len, MSG_NOSIGNAL); if (nbyte == len) { lua_pushinteger(L, ctx->len); lua_pushnil(L); break; } else if (nbyte == -1 && errno != EAGAIN) { lua_pushinteger(L, ctx->idx); lua_pushinteger(L, errno); break; } else if (nbyte == -1) { lua_pushinteger(L, LAS_S_YIELD_FOR_IO); lua_pushlightuserdata(L, res); lua_pushinteger(L, LAS_S_WAIT_FOR_OUTPUT); lua_pushinteger(L, LAS_D_TIMOUT_SECS); return lua_yieldk(L, 4, (lua_KContext)ctx, k_socket_send); } else { ctx->idx += nbyte; } } memp_recycle(ctx); return 2; }
// wait() // wait blocks (yields to the C code), waiting until the user is ready to continue. // Call this in situations where a "press any key to continue" prompt would be appropriate. int _lua_wait(lua_State *L) { _talk_state *st = (_talk_state*) lua_touserdata(L, lua_upvalueindex(1)); int ctx, status; if (st->m_iState == _STOPPED) { return luaL_error(L, "conversation is already stopped"); } status = lua_getctx(L, &ctx); if (status == LUA_YIELD) { return 0; } st->m_iState = _WAIT_ANY; st->m_pThread = L; return lua_yieldk(L, 0, 0, _lua_wait); }
static int auxresume (lua_State *L, lua_State *co, int narg) { int status, stacks; int ismain = lua_pushthread(L); lua_pop(L, 1); if (ismain) { lua_pushliteral(L, "cannot call resume in main thread"); return -1; /* error flag */ } if (!lua_checkstack(co, narg)) { lua_pushliteral(L, "too many arguments to resume"); return -1; /* error flag */ } if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) { lua_pushliteral(L, "cannot resume dead coroutine"); return -1; /* error flag */ } lua_xmove(L, co, narg); context_lua_t *lctx = context_lua_t::lua_get_context(L); while (((status = lua_resume(co, L, narg)) == LUA_YIELD) && lctx->yielding_up()) { /* can happen only when status == LUA_YIELD */ if ((stacks = lua_checkstack(L, LUA_MINSTACK)) && lua_yieldable(L)) { /* reserve LUA_MINSTACK stack for resume result */ return lua_yieldk(L, 0, 0, coresume_continue); /* yield again! n(0) result to yield and ctx(0) is not allowed */ } else { /* lua_gettop(co) must be 0 since context_lua_t::lua_yield_send yield 0 result */ int yieldup_status = stacks ? NL_EYIELD : NL_ESTACKLESS; lctx->yielding_finalize(NULL, yieldup_status); lua_pushboolean(co, 0); /* stack on co must be enough since we have checked it at last yield */ lua_pushinteger(co, yieldup_status); lua_pushnil(co); lua_pushnil(co); narg = 4; } } if (status == LUA_OK || status == LUA_YIELD) { int nres = lua_gettop(co); if (!lua_checkstack(L, nres + 1)) { lua_pop(co, nres); /* remove results anyway */ lua_pushliteral(L, "too many results to resume"); return -1; /* error flag */ } lua_xmove(co, L, nres); /* move yielded values */ return nres; } else { lua_xmove(co, L, 1); /* move error message */ return -1; /* error flag */ } }
// offerChoice() // offerChoice blocks (yields to the C code) until the user makes a choice, returning // the 1-based index of the chosen option. int _lua_offerchoice(lua_State *L) { _talk_state *st = (_talk_state*) lua_touserdata(L, lua_upvalueindex(1)); int ctx, status; if (st->m_iState == _STOPPED) { return luaL_error(L, "conversation is already stopped"); } status = lua_getctx(L, &ctx); if (status == LUA_YIELD) { return 1; // choice should be pushed on the stack before resuming } if (status != LUA_OK) { sys_abort(); } menu_auto_resize(st->m_pChoices); st->m_iState = _WAIT_CHOICE; st->m_pThread = L; return lua_yieldk(L, 0, 0, _lua_offerchoice); }
int lua_engine::emu_wait(lua_State *L) { luaL_argcheck(L, lua_isnumber(L, 1), 1, "waiting duration expected"); machine().scheduler().timer_set(attotime::from_double(lua_tonumber(L, 1)), timer_expired_delegate(FUNC(lua_engine::resume), this), 0, L); return lua_yieldk(L, 0, 0, 0); }
LUA_API int luaS_yield(lua_State *L, int nrets) { int ret = lua_yieldk(L, nrets, 0, k); return ret; }
LUA_API int luaS_yield(lua_State *L, int nrets) { return k(L, lua_yieldk(L, nrets, 0, k), 0); }