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::string action = elts[index].action();
|
||||||
std::cerr << "Invoking plan: " << action << std::endl;
|
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) {
|
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();
|
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.
|
// Validate that the action is legal.
|
||||||
Gui validation_gui;
|
Gui validation_gui;
|
||||||
update_gui(actor_id, place_id, &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;
|
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;
|
// Set up for Lua manipulation.
|
||||||
LuaStack LS(L, actor, place, ugui, func, tangibles, mt, index, actions, thread, message);
|
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.
|
// Get the actor and place.
|
||||||
LS.rawget(tangibles, LuaRegistry, "tangibles");
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct the userdata with the GUI pointer.
|
|
||||||
LS.newpointer<Gui>(ugui, gui, false);
|
|
||||||
|
|
||||||
// Create a new thread, set up function and parameters.
|
// Create a new thread, set up function and parameters.
|
||||||
lua_State *CO = LS.newthread(thread);
|
lua_State *CO = LS.newthread(thread);
|
||||||
lua_pushvalue(L, func.index());
|
lua_pushvalue(L, func.index());
|
||||||
lua_pushvalue(L, actor.index());
|
lua_pushvalue(L, actor.index());
|
||||||
lua_pushvalue(L, place.index());
|
lua_pushvalue(L, place.index());
|
||||||
lua_pushvalue(L, ugui.index());
|
lua_pushnil(L); // Gui state not implemented yet.
|
||||||
lua_xmove(L, CO, 4);
|
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);
|
int status = lua_resume(CO, 3);
|
||||||
|
|
||||||
// Three possible outcomes: finished, yielded, or errored.
|
// Three possible outcomes: finished, yielded, or errored.
|
||||||
if (status == LUA_YIELD) {
|
if (status == LUA_YIELD) {
|
||||||
// Yield not implemented yet. The coroutine is simply dropped.
|
// When the wait statement yields, it yields the desired timestamp.
|
||||||
std::cerr << "Thread yield not implemented yet." << std::endl;
|
std::cerr << "Thread yield top = " << lua_gettop(CO) << std::endl;
|
||||||
|
LS.rawset(threads, tid, LuaNil);
|
||||||
} else if (status == 0) {
|
} else if (status == 0) {
|
||||||
// Successfully ran to completion.
|
// Successfully ran to completion. Remove from thread table.
|
||||||
std::cerr << "Thread ran to completion." << std::endl;
|
std::cerr << "Thread ran to completion." << std::endl;
|
||||||
|
LS.rawset(threads, tid, LuaNil);
|
||||||
} else {
|
} else {
|
||||||
// Transfer the error message from CO to L, and add a traceback.
|
// Transfer the error message from CO to L, and add a traceback.
|
||||||
|
LS.rawset(threads, tid, LuaNil);
|
||||||
traceback_coroutine(L, CO);
|
traceback_coroutine(L, CO);
|
||||||
std::cerr << lua_tostring(L, -1);
|
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();
|
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") {
|
LuaDefine(tangible_get, "c") {
|
||||||
LuaArg id;
|
LuaArg id;
|
||||||
LuaRet database;
|
LuaRet database;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "source.hpp"
|
#include "source.hpp"
|
||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
#include "luasnap.hpp"
|
#include "luasnap.hpp"
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
@@ -44,6 +46,10 @@ public:
|
|||||||
|
|
||||||
class World {
|
class World {
|
||||||
public:
|
public:
|
||||||
|
// A thread ID appended to a place ID.
|
||||||
|
//
|
||||||
|
using ThreadPair = std::pair<int64_t, int64_t>;
|
||||||
|
|
||||||
// A lua intepreter with snapshot function.
|
// A lua intepreter with snapshot function.
|
||||||
//
|
//
|
||||||
LuaSnap lua_snap_;
|
LuaSnap lua_snap_;
|
||||||
@@ -58,6 +64,14 @@ public:
|
|||||||
PlaneMap plane_map_;
|
PlaneMap plane_map_;
|
||||||
std::unordered_map<int64_t, Tangible> tangibles_;
|
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:
|
public:
|
||||||
// Constructor.
|
// Constructor.
|
||||||
//
|
//
|
||||||
@@ -114,7 +128,9 @@ public:
|
|||||||
|
|
||||||
// Invoke an action plan.
|
// 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
|
// fetch
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -21,6 +21,4 @@ end
|
|||||||
|
|
||||||
function player.action.west(actor, place, gui)
|
function player.action.west(actor, place, gui)
|
||||||
print("Moving west")
|
print("Moving west")
|
||||||
t = nil
|
|
||||||
t[3] = 5
|
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user