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_isyieldable(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 */ } }
int jass_call_closure(lua_State* L) { if (!is_gaming()) { lua_pushnil(L); return 1; } int result = jass_call_native_function(L, (const jass::func_value*)lua_tointeger(L, lua_upvalueindex(1))); if (lua_isyieldable(L)) { jass_vm_t* thread = get_jass_thread(); if (thread && thread->has_sleep) { thread->opcode -= jass::trampoline_size() / sizeof(jass::opcode); return lua_yield(L, 0); } } return result; }
static int luaB_yieldable (lua_State *L) { lua_pushboolean(L, lua_isyieldable(L)); return 1; }
int jass_call_native_function(lua_State* L, const jass::func_value* nf, uintptr_t func_address) { LUA_PERFTRACE(kJassCall); if (!lua_isyieldable(L) && nf->has_sleep()) { printf("Wanring: %s is disable.\n", lua_tostring(L, lua_upvalueindex(1))); lua_pushnil(L); return 1; } size_t param_size = nf->get_param().size(); if ((int)param_size > lua_gettop(L)) { lua_pushnil(L); return 1; } jass::call_param param(param_size); for (size_t i = 0; i < param_size; ++i) { jass::variable_type vt = nf->get_param()[i]; switch (vt) { case jass::TYPE_BOOLEAN: param.push(i, jassbind::read_boolean(L, i + 1)); break; case jass::TYPE_CODE: param.push(i, jassbind::read_code(L, i + 1)); break; case jass::TYPE_HANDLE: param.push(i, jassbind::read_handle(L, i + 1)); break; case jass::TYPE_INTEGER: param.push(i, jassbind::read_integer(L, i + 1)); break; case jass::TYPE_REAL: param.push_real(i, jassbind::read_real(L, i + 1)); break; case jass::TYPE_STRING: param.push(i, lua_tostring(L, i + 1)); break; default: param.push(i, 0); break; } } if (func_address == 0) func_address = nf->get_address(); uintptr_t retval = 0; if (runtime::catch_crash) { retval = safe_jass_call(L, func_address, param.data(), param_size); } else { retval = jass::call(func_address, param.data(), param_size); } if (nf->get_return() == jass::TYPE_STRING) { retval = get_jass_vm()->string_table->get(retval); } return jass_push(L, nf->get_return(), retval) ? 1 : 0; }