From 5f783e643b63d380e7eb17be9c35674f57802a79 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Sat, 20 Feb 2021 19:17:20 -0500 Subject: [PATCH] More work on thread scheduling and tracebacks --- luprex/core/cpp/luastack.hpp | 2 +- luprex/core/cpp/sched.hpp | 1 + luprex/core/cpp/traceback.cpp | 26 +++++++++++--------------- luprex/core/cpp/traceback.hpp | 6 +++--- luprex/core/cpp/world.cpp | 33 +++++++++++++++++++++++---------- luprex/core/cpp/world.hpp | 2 +- luprex/core/lua/player.lua | 4 ++++ 7 files changed, 44 insertions(+), 30 deletions(-) diff --git a/luprex/core/cpp/luastack.hpp b/luprex/core/cpp/luastack.hpp index cc9efd0c..e62a85c4 100644 --- a/luprex/core/cpp/luastack.hpp +++ b/luprex/core/cpp/luastack.hpp @@ -504,7 +504,7 @@ public: push_any_value(value); lua_rawset(L_, tab); } - + // template // void rawset(LuaSlot tab, const char *field, VT value) const { // push_any_value(value); diff --git a/luprex/core/cpp/sched.hpp b/luprex/core/cpp/sched.hpp index 47e0d3d1..d01c93b8 100644 --- a/luprex/core/cpp/sched.hpp +++ b/luprex/core/cpp/sched.hpp @@ -11,6 +11,7 @@ private: int64_t clock_; int64_t thread_id_; int64_t place_id_; + int func_args_; public: int64_t clock() const { return clock_; } diff --git a/luprex/core/cpp/traceback.cpp b/luprex/core/cpp/traceback.cpp index ae00d732..453d8e5c 100644 --- a/luprex/core/cpp/traceback.cpp +++ b/luprex/core/cpp/traceback.cpp @@ -5,7 +5,9 @@ // Call this with the error message on top of the stack. -static void traceback_general(lua_State *L, lua_State *L1, int baselevel) { +// The error message is replaced with a traceback. +// +int traceback_coroutine(lua_State *L) { int top = lua_gettop(L); // Convert message to a string @@ -23,22 +25,24 @@ static void traceback_general(lua_State *L, lua_State *L1, int baselevel) { // Append the traceback. lua_Debug ar; - int level = baselevel; int firstpart = 1; - while (lua_getstack(L1, level++, &ar)) { + for (int level = 0; lua_getstack(L, level, &ar); level++) { if (level > TRACEBACK_LEVELS1 && firstpart) { /* no more than `LEVELS2' more levels? */ - if (!lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) + if (!lua_getstack(L, level + TRACEBACK_LEVELS2, &ar)) level--; /* keep going */ else { lua_pushliteral(L, "\n\t..."); /* too many levels */ - while (lua_getstack(L1, level + TRACEBACK_LEVELS2, &ar)) /* find last levels */ + while (lua_getstack(L, level + TRACEBACK_LEVELS2, &ar)) /* find last levels */ level++; } firstpart = 0; continue; } - lua_getinfo(L1, "Snl", &ar); + lua_getinfo(L, "Snl", &ar); + if ((level == 0) && (*ar.what == 'C') && (std::string(ar.name) == "__newindex")) { + continue; + } if ((ar.currentline > 0) || (*ar.namewhat != 0) || (*ar.what != 'C')) { lua_pushliteral(L, "\n\t"); lua_pushfstring(L, "%s:", ar.short_src); @@ -64,22 +68,14 @@ static void traceback_general(lua_State *L, lua_State *L1, int baselevel) { if (1 + lua_gettop(L) - top > 1) { lua_concat(L, 1 + lua_gettop(L) - top); } -} - -int traceback_handler(lua_State *L) { - traceback_general(L, L, 1); return 1; } -void traceback_coroutine(lua_State *L, lua_State *CO) { - lua_xmove(CO, L, 1); - traceback_general(L, CO, 0); -} int traceback_pcall(lua_State *L, int narg, int nret) { int status; int base = lua_gettop(L) - narg; /* function index */ - lua_pushcfunction(L, traceback_handler); /* push traceback function */ + lua_pushcfunction(L, traceback_coroutine); /* push traceback function */ lua_insert(L, base); /* put it under chunk and args */ status = lua_pcall(L, narg, nret, base); lua_remove(L, base); /* remove traceback function */ diff --git a/luprex/core/cpp/traceback.hpp b/luprex/core/cpp/traceback.hpp index 05407005..36577485 100644 --- a/luprex/core/cpp/traceback.hpp +++ b/luprex/core/cpp/traceback.hpp @@ -15,10 +15,10 @@ // traceback_coroutine // -// Given a coroutine which contains an error message, pop the error -// message from the coroutine, and push a traceback onto L. +// Given a coroutine which contains an error message, replace +// the error message with a full traceback. Always returns 1. // -void traceback_coroutine(lua_State *L, lua_State *CO); +int traceback_coroutine(lua_State *L); // traceback_pcall // diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index a96e09cf..e364a608 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -118,7 +118,6 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) { // Populate the database and metatable with initial stuff. LS.rawset(database, "inventory", LuaNewTable); - LS.rawset(database, "id", id); LS.rawset(metatab, "id", id); LS.rawset(metatab, "threads", LuaNewTable); // LS.rawset(metatab, "__metatable", LuaNil); @@ -258,14 +257,13 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a } LS.rawset(threads, tid, thread); LS.result(); - + // Push the thread's ID into the runnable thread queue, // then run the thread queue. thread_sched_.add(0, tid, place_id); run_scheduled_threads(0); } - void World::run_scheduled_threads(int64_t clk) { lua_State *L = state(); LuaVar tangibles, place, mt, threads, thread; @@ -293,23 +291,31 @@ void World::run_scheduled_threads(int64_t clk) { // Resume the coroutine. lua_State *CO = LS.ckthread(thread); - int status = lua_resume(CO, 3); + int top = lua_gettop(CO); + int status = lua_resume(CO, (top > 0) ? (top - 1) : 0); // Three possible outcomes: finished, yielded, or errored. if (status == LUA_YIELD) { // When the wait statement yields, it yields the desired timestamp. - std::cerr << "Thread yield top = " << lua_gettop(CO) << std::endl; - // TODO: Insert the thread back into thread_sched_. - LS.rawset(threads, sched.thread_id(), LuaNil); + if ((lua_gettop(CO) != 1) || (!lua_isnumber(CO, 1))) { + std::cerr << "Thread yielded incorrectly. Killing it." << std::endl; + LS.rawset(threads, sched.thread_id(), LuaNil); + } else { + lua_Number delay = lua_tonumber(CO, 1); + lua_settop(CO, 0); + std::cerr << "Thread wait = " << delay << std::endl; + thread_sched_.add(sched.clock() + int64_t(delay), sched.thread_id(), sched.place_id()); + std::cerr << "Added to schedule." << std::endl; + } } else if (status == 0) { // Successfully ran to completion. Remove from thread table. std::cerr << "Thread ran to completion." << std::endl; LS.rawset(threads, sched.thread_id(), LuaNil); } else { - // Transfer the error message from CO to L, and add a traceback. + // Generated an error. Add a traceback, print, and kill the coroutine. + traceback_coroutine(CO); + std::cerr << lua_tostring(CO, -1); LS.rawset(threads, sched.thread_id(), LuaNil); - traceback_coroutine(L, CO); - std::cerr << lua_tostring(L, -1); } } LS.result(); @@ -330,3 +336,10 @@ LuaDefine(tangible_make, "c") { World::fetch(L)->tangible_make(L, 0, true); return 1; } + +LuaDefine(world_wait, "f") { + if (lua_type(L, -1) != LUA_TNUMBER) { + luaL_error(L, "Argument to wait must be a number."); + } + return lua_yield(L, 1); +} diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index b0f10807..29b68e1a 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -61,7 +61,7 @@ public: PlaneMap plane_map_; std::unordered_map tangibles_; - // Thread schedule: should include every thread, except + // Thread schedule: must include every thread, except // for the one currently-executing thread. // Schedule thread_sched_; diff --git a/luprex/core/lua/player.lua b/luprex/core/lua/player.lua index b5d8a044..26089723 100644 --- a/luprex/core/lua/player.lua +++ b/luprex/core/lua/player.lua @@ -17,8 +17,12 @@ end function player.action.east(actor, place, gui) print("Moving east") + t = nil + t[3] = 4 end function player.action.west(actor, place, gui) print("Moving west") + wait(0) + print("Moving west again") end