From 36ff4eacaee30c7f57124f62610d0847674ef068 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Thu, 18 Feb 2021 17:21:25 -0500 Subject: [PATCH] Added class Schedule for threads --- luprex/core/Makefile | 1 + luprex/core/cpp/sched.cpp | 27 +++++++++++ luprex/core/cpp/sched.hpp | 39 ++++++++++++++++ luprex/core/cpp/world.cpp | 95 +++++++++++++++++---------------------- luprex/core/cpp/world.hpp | 15 +++---- 5 files changed, 113 insertions(+), 64 deletions(-) create mode 100644 luprex/core/cpp/sched.cpp create mode 100644 luprex/core/cpp/sched.hpp diff --git a/luprex/core/Makefile b/luprex/core/Makefile index b1b28f9e..6e0fd9d7 100644 --- a/luprex/core/Makefile +++ b/luprex/core/Makefile @@ -9,6 +9,7 @@ CPP_FILES=\ cpp/luaconsole.cpp\ cpp/idalloc.cpp\ cpp/globaldb.cpp\ + cpp/sched.cpp\ cpp/table.cpp\ cpp/gui.cpp\ cpp/luasnap.cpp\ diff --git a/luprex/core/cpp/sched.cpp b/luprex/core/cpp/sched.cpp new file mode 100644 index 00000000..703c70a2 --- /dev/null +++ b/luprex/core/cpp/sched.cpp @@ -0,0 +1,27 @@ + +#include "sched.hpp" + +bool SchedEntry::operator < (const SchedEntry &other) const { + if (clock_ < other.clock_) return true; + if (clock_ > other.clock_) return false; + if (thread_id_ < other.thread_id_) return true; + if (thread_id_ > other.thread_id_) return false; + if (place_id_ < other.place_id_) return true; + if (place_id_ > other.place_id_) return false; + return false; +} + +void Schedule::add(int64_t clk, int64_t thid, int64_t plid) { + schedule_.insert(SchedEntry(clk, thid, plid)); +} + +bool Schedule::ready(int64_t clk) const { + return (!schedule_.empty()) && (schedule_.begin()->clock() <= clk); +} + +SchedEntry Schedule::pop() { + SchedEntry result = *schedule_.begin(); + schedule_.erase(schedule_.begin()); + return result; +} + diff --git a/luprex/core/cpp/sched.hpp b/luprex/core/cpp/sched.hpp new file mode 100644 index 00000000..47e0d3d1 --- /dev/null +++ b/luprex/core/cpp/sched.hpp @@ -0,0 +1,39 @@ +#ifndef SCHED_HPP +#define SCHED_HPP + +#include +#include + +class SchedEntry { +private: + friend class Schedule; + + int64_t clock_; + int64_t thread_id_; + int64_t place_id_; + +public: + int64_t clock() const { return clock_; } + int64_t thread_id() const { return thread_id_; } + int64_t place_id() const { return place_id_; } + + SchedEntry(int64_t clk, int64_t thid, int64_t plid) { + clock_ = clk; + thread_id_ = thid; + place_id_ = plid; + } + + bool operator < (const SchedEntry &other) const; +}; + +class Schedule { +private: + std::set schedule_; +public: + void add(int64_t clk, int64_t thid, int64_t plid); + bool ready(int64_t clk) const; + SchedEntry pop(); +}; + +#endif // SCHED_HPP + diff --git a/luprex/core/cpp/world.cpp b/luprex/core/cpp/world.cpp index 480d171f..a96e09cf 100644 --- a/luprex/core/cpp/world.cpp +++ b/luprex/core/cpp/world.cpp @@ -261,73 +261,60 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a // Push the thread's ID into the runnable thread queue, // then run the thread queue. - enqueue_thread(tid, place_id); - run_thread_queue(); + thread_sched_.add(0, tid, place_id); + run_scheduled_threads(0); } -void World::enqueue_thread(int64_t tid, int64_t place_id) { - thread_queue_.insert(std::make_pair(tid, place_id)); -} -void World::run_thread(int64_t tid, int64_t place_id) { +void World::run_scheduled_threads(int64_t clk) { lua_State *L = state(); LuaVar tangibles, place, mt, threads, thread; LuaStack LS(L, tangibles, place, mt, threads, thread); - LS.rawget(tangibles, LuaRegistry, "tangibles"); - LS.rawget(place, tangibles, place_id); - if (!LS.istable(place)) { - LS.result(); - return; - } - LS.getmetatable(mt, place); - if (!LS.istable(mt)) { - LS.result(); - return; - } - LS.rawget(threads, mt, "threads"); - if (!LS.istable(threads)) { - LS.result(); - return; - } - LS.rawget(thread, threads, tid); - if (!LS.isthread(thread)) { - LS.result(); - return; - } - // Resume the coroutine. - lua_State *CO = LS.ckthread(thread); - int status = lua_resume(CO, 3); + while (thread_sched_.ready(clk)) { + SchedEntry sched = thread_sched_.pop(); + LS.rawget(place, tangibles, sched.place_id()); + if (!LS.istable(place)) { + continue; + } + LS.getmetatable(mt, place); + if (!LS.istable(mt)) { + continue; + } + LS.rawget(threads, mt, "threads"); + if (!LS.istable(threads)) { + continue; + } + LS.rawget(thread, threads, sched.thread_id()); + if (!LS.isthread(thread)) { + continue; + } - // 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; - LS.rawset(threads, tid, LuaNil); - } else if (status == 0) { - // Successfully ran to completion. Remove from thread table. - std::cerr << "Thread ran to completion." << std::endl; - LS.rawset(threads, tid, LuaNil); - } else { - // Transfer the error message from CO to L, and add a traceback. - LS.rawset(threads, tid, LuaNil); - traceback_coroutine(L, CO); - std::cerr << lua_tostring(L, -1); + // Resume the coroutine. + lua_State *CO = LS.ckthread(thread); + int status = lua_resume(CO, 3); + + // 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); + } 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. + LS.rawset(threads, sched.thread_id(), LuaNil); + traceback_coroutine(L, CO); + std::cerr << lua_tostring(L, -1); + } } LS.result(); } -void World::run_thread_queue() { - while (!thread_queue_.empty()) { - auto iter = thread_queue_.begin(); - int64_t tid = iter->first; - int64_t place_id = iter->second; - run_thread(tid, place_id); - thread_queue_.erase(iter); - } -} - LuaDefine(tangible_get, "c") { LuaArg id; LuaRet database; diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index b2e64f1d..b0f10807 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -6,6 +6,7 @@ #include "planemap.hpp" #include "idalloc.hpp" #include "animqueue.hpp" +#include "sched.hpp" #include "source.hpp" #include "gui.hpp" #include "luasnap.hpp" @@ -46,10 +47,6 @@ public: class World { public: - // A thread ID appended to a place ID. - // - using ThreadPair = std::pair; - // A lua intepreter with snapshot function. // LuaSnap lua_snap_; @@ -64,14 +61,12 @@ public: PlaneMap plane_map_; std::unordered_map tangibles_; - // Thread queue. + // Thread schedule: should include every thread, except + // for the one currently-executing thread. // - std::set thread_queue_; - - void enqueue_thread(int64_t tid, int64_t place_id); - void run_thread_queue(); - void run_thread(int64_t tid, int64_t place_id); + Schedule thread_sched_; + void run_scheduled_threads(int64_t clk); public: // Constructor. //