Added a thread queue
This commit is contained in:
@@ -122,7 +122,7 @@ void TextGame::do_choose_command(const StringVec &cmd) {
|
||||
}
|
||||
std::string action = elts[index].action();
|
||||
std::cerr << "Invoking plan: " << action << std::endl;
|
||||
world_->invoke_plan(1, gui_place_, action, &gui_);
|
||||
world_->invoke_plan(1, gui_place_, action);
|
||||
}
|
||||
|
||||
void TextGame::do_snapshot_command(const StringVec &cmd) {
|
||||
|
||||
@@ -193,7 +193,7 @@ void World::update_gui(int64_t actor_id, int64_t place_id, Gui *gui) {
|
||||
LS.result();
|
||||
}
|
||||
|
||||
void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, Gui *gui) {
|
||||
void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action) {
|
||||
// Validate that the action is legal.
|
||||
Gui validation_gui;
|
||||
update_gui(actor_id, place_id, &validation_gui);
|
||||
@@ -201,10 +201,15 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
||||
return;
|
||||
}
|
||||
|
||||
lua_State *L = state();
|
||||
// Get an ID batch for the thread, and take one for the thread itself.
|
||||
Tangible *tactor = tangible_get(actor_id);
|
||||
int64_t id_batch = tactor->id_player_pool_->get_batch();
|
||||
int64_t tid = id_batch++;
|
||||
|
||||
LuaVar actor, place, ugui, func, tangibles, mt, index, actions, thread, message;
|
||||
LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index, actions, thread, message);
|
||||
// Set up for Lua manipulation.
|
||||
lua_State *L = state();
|
||||
LuaVar actor, place, func, tangibles, mt, index, actions, threadtab, thread, threadinfo, message;
|
||||
LuaStack LS(L, actor, place, func, tangibles, mt, index, actions, threadtab, thread, threadinfo, message);
|
||||
|
||||
// Get the actor and place.
|
||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
||||
@@ -237,40 +242,100 @@ void World::invoke_plan(int64_t actor_id, int64_t place_id, const std::string &a
|
||||
return;
|
||||
}
|
||||
|
||||
// Construct the userdata with the GUI pointer.
|
||||
LS.newpointer<Gui>(ugui, gui, false);
|
||||
|
||||
// Create a new thread, set up function and parameters.
|
||||
lua_State *CO = LS.newthread(thread);
|
||||
lua_pushvalue(L, func.index());
|
||||
lua_pushvalue(L, actor.index());
|
||||
lua_pushvalue(L, place.index());
|
||||
lua_pushvalue(L, ugui.index());
|
||||
lua_pushnil(L); // Gui state not implemented yet.
|
||||
lua_xmove(L, CO, 4);
|
||||
|
||||
// Resume the new coroutine.
|
||||
// Store the thread into place's thread table.
|
||||
LS.rawget(threadtab, mt, "threads");
|
||||
if (!LS.istable(threadtab)) {
|
||||
LS.result();
|
||||
return;
|
||||
}
|
||||
LS.set(threadinfo, LuaNewTable);
|
||||
LS.rawset(threadinfo, "thread", thread);
|
||||
LS.rawset(threadtab, tid, threadinfo);
|
||||
LS.result();
|
||||
|
||||
// Push the thread's ID into the runnable thread queue,
|
||||
// then run the thread queue.
|
||||
enqueue_thread(tid, place_id);
|
||||
run_thread_queue();
|
||||
}
|
||||
|
||||
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) {
|
||||
lua_State *L = state();
|
||||
LuaVar tangibles, place, mt, threads, threadtab, thread;
|
||||
LuaStack LS(L, tangibles, place, mt, threads, threadtab, 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(threadtab, threads, tid);
|
||||
if (!LS.istable(threadtab)) {
|
||||
LS.result();
|
||||
return;
|
||||
}
|
||||
LS.rawget(thread, threadtab, "thread");
|
||||
if (!LS.isthread(thread)) {
|
||||
LS.result();
|
||||
return;
|
||||
}
|
||||
LS.rawset(threadtab, "wake", LuaNil);
|
||||
|
||||
// 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) {
|
||||
// Yield not implemented yet. The coroutine is simply dropped.
|
||||
std::cerr << "Thread yield not implemented yet." << std::endl;
|
||||
// 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.
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Nuke the userdata, in case somebody saved a pointer to it.
|
||||
LS.clearuserdata(ugui);
|
||||
|
||||
// And we're done.
|
||||
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;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "source.hpp"
|
||||
#include "gui.hpp"
|
||||
#include "luasnap.hpp"
|
||||
#include <set>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -44,6 +46,10 @@ public:
|
||||
|
||||
class World {
|
||||
public:
|
||||
// A thread ID appended to a place ID.
|
||||
//
|
||||
using ThreadPair = std::pair<int64_t, int64_t>;
|
||||
|
||||
// A lua intepreter with snapshot function.
|
||||
//
|
||||
LuaSnap lua_snap_;
|
||||
@@ -58,6 +64,14 @@ public:
|
||||
PlaneMap plane_map_;
|
||||
std::unordered_map<int64_t, Tangible> tangibles_;
|
||||
|
||||
// Thread queue.
|
||||
//
|
||||
std::set<ThreadPair> 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);
|
||||
|
||||
public:
|
||||
// Constructor.
|
||||
//
|
||||
@@ -114,7 +128,9 @@ public:
|
||||
|
||||
// Invoke an action plan.
|
||||
//
|
||||
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action, Gui *gui);
|
||||
// Eventually we'll add another parameter for gui-state.
|
||||
//
|
||||
void invoke_plan(int64_t actor_id, int64_t place_id, const std::string &action);
|
||||
|
||||
// fetch
|
||||
//
|
||||
|
||||
@@ -21,6 +21,4 @@ end
|
||||
|
||||
function player.action.west(actor, place, gui)
|
||||
print("Moving west")
|
||||
t = nil
|
||||
t[3] = 5
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user