Added a thread queue

This commit is contained in:
2021-02-18 14:56:12 -05:00
parent 213bf12425
commit 1dcf0494ef
4 changed files with 100 additions and 21 deletions

View File

@@ -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;