More work on thread scheduling and tracebacks
This commit is contained in:
@@ -504,7 +504,7 @@ public:
|
|||||||
push_any_value(value);
|
push_any_value(value);
|
||||||
lua_rawset(L_, tab);
|
lua_rawset(L_, tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
// template<typename VT>
|
// template<typename VT>
|
||||||
// void rawset(LuaSlot tab, const char *field, VT value) const {
|
// void rawset(LuaSlot tab, const char *field, VT value) const {
|
||||||
// push_any_value(value);
|
// push_any_value(value);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ private:
|
|||||||
int64_t clock_;
|
int64_t clock_;
|
||||||
int64_t thread_id_;
|
int64_t thread_id_;
|
||||||
int64_t place_id_;
|
int64_t place_id_;
|
||||||
|
int func_args_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int64_t clock() const { return clock_; }
|
int64_t clock() const { return clock_; }
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
|
|
||||||
// Call this with the error message on top of the stack.
|
// 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);
|
int top = lua_gettop(L);
|
||||||
|
|
||||||
// Convert message to a string
|
// Convert message to a string
|
||||||
@@ -23,22 +25,24 @@ static void traceback_general(lua_State *L, lua_State *L1, int baselevel) {
|
|||||||
|
|
||||||
// Append the traceback.
|
// Append the traceback.
|
||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
int level = baselevel;
|
|
||||||
int firstpart = 1;
|
int firstpart = 1;
|
||||||
while (lua_getstack(L1, level++, &ar)) {
|
for (int level = 0; lua_getstack(L, level, &ar); level++) {
|
||||||
if (level > TRACEBACK_LEVELS1 && firstpart) {
|
if (level > TRACEBACK_LEVELS1 && firstpart) {
|
||||||
/* no more than `LEVELS2' more levels? */
|
/* 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 */
|
level--; /* keep going */
|
||||||
else {
|
else {
|
||||||
lua_pushliteral(L, "\n\t..."); /* too many levels */
|
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++;
|
level++;
|
||||||
}
|
}
|
||||||
firstpart = 0;
|
firstpart = 0;
|
||||||
continue;
|
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')) {
|
if ((ar.currentline > 0) || (*ar.namewhat != 0) || (*ar.what != 'C')) {
|
||||||
lua_pushliteral(L, "\n\t");
|
lua_pushliteral(L, "\n\t");
|
||||||
lua_pushfstring(L, "%s:", ar.short_src);
|
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) {
|
if (1 + lua_gettop(L) - top > 1) {
|
||||||
lua_concat(L, 1 + lua_gettop(L) - top);
|
lua_concat(L, 1 + lua_gettop(L) - top);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int traceback_handler(lua_State *L) {
|
|
||||||
traceback_general(L, L, 1);
|
|
||||||
return 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 traceback_pcall(lua_State *L, int narg, int nret) {
|
||||||
int status;
|
int status;
|
||||||
int base = lua_gettop(L) - narg; /* function index */
|
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 */
|
lua_insert(L, base); /* put it under chunk and args */
|
||||||
status = lua_pcall(L, narg, nret, base);
|
status = lua_pcall(L, narg, nret, base);
|
||||||
lua_remove(L, base); /* remove traceback function */
|
lua_remove(L, base); /* remove traceback function */
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
|
|
||||||
// traceback_coroutine
|
// traceback_coroutine
|
||||||
//
|
//
|
||||||
// Given a coroutine which contains an error message, pop the error
|
// Given a coroutine which contains an error message, replace
|
||||||
// message from the coroutine, and push a traceback onto L.
|
// 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
|
// traceback_pcall
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ Tangible *World::tangible_make(lua_State *L, int64_t id, bool pushdb) {
|
|||||||
|
|
||||||
// Populate the database and metatable with initial stuff.
|
// Populate the database and metatable with initial stuff.
|
||||||
LS.rawset(database, "inventory", LuaNewTable);
|
LS.rawset(database, "inventory", LuaNewTable);
|
||||||
LS.rawset(database, "id", id);
|
|
||||||
LS.rawset(metatab, "id", id);
|
LS.rawset(metatab, "id", id);
|
||||||
LS.rawset(metatab, "threads", LuaNewTable);
|
LS.rawset(metatab, "threads", LuaNewTable);
|
||||||
// LS.rawset(metatab, "__metatable", LuaNil);
|
// 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.rawset(threads, tid, thread);
|
||||||
LS.result();
|
LS.result();
|
||||||
|
|
||||||
// Push the thread's ID into the runnable thread queue,
|
// Push the thread's ID into the runnable thread queue,
|
||||||
// then run the thread queue.
|
// then run the thread queue.
|
||||||
thread_sched_.add(0, tid, place_id);
|
thread_sched_.add(0, tid, place_id);
|
||||||
run_scheduled_threads(0);
|
run_scheduled_threads(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void World::run_scheduled_threads(int64_t clk) {
|
void World::run_scheduled_threads(int64_t clk) {
|
||||||
lua_State *L = state();
|
lua_State *L = state();
|
||||||
LuaVar tangibles, place, mt, threads, thread;
|
LuaVar tangibles, place, mt, threads, thread;
|
||||||
@@ -293,23 +291,31 @@ void World::run_scheduled_threads(int64_t clk) {
|
|||||||
|
|
||||||
// Resume the coroutine.
|
// Resume the coroutine.
|
||||||
lua_State *CO = LS.ckthread(thread);
|
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.
|
// Three possible outcomes: finished, yielded, or errored.
|
||||||
if (status == LUA_YIELD) {
|
if (status == LUA_YIELD) {
|
||||||
// When the wait statement yields, it yields the desired timestamp.
|
// When the wait statement yields, it yields the desired timestamp.
|
||||||
std::cerr << "Thread yield top = " << lua_gettop(CO) << std::endl;
|
if ((lua_gettop(CO) != 1) || (!lua_isnumber(CO, 1))) {
|
||||||
// TODO: Insert the thread back into thread_sched_.
|
std::cerr << "Thread yielded incorrectly. Killing it." << std::endl;
|
||||||
LS.rawset(threads, sched.thread_id(), LuaNil);
|
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) {
|
} else if (status == 0) {
|
||||||
// Successfully ran to completion. Remove from thread table.
|
// 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, sched.thread_id(), LuaNil);
|
LS.rawset(threads, sched.thread_id(), LuaNil);
|
||||||
} else {
|
} 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);
|
LS.rawset(threads, sched.thread_id(), LuaNil);
|
||||||
traceback_coroutine(L, CO);
|
|
||||||
std::cerr << lua_tostring(L, -1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LS.result();
|
LS.result();
|
||||||
@@ -330,3 +336,10 @@ LuaDefine(tangible_make, "c") {
|
|||||||
World::fetch(L)->tangible_make(L, 0, true);
|
World::fetch(L)->tangible_make(L, 0, true);
|
||||||
return 1;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public:
|
|||||||
PlaneMap plane_map_;
|
PlaneMap plane_map_;
|
||||||
std::unordered_map<int64_t, Tangible> tangibles_;
|
std::unordered_map<int64_t, Tangible> tangibles_;
|
||||||
|
|
||||||
// Thread schedule: should include every thread, except
|
// Thread schedule: must include every thread, except
|
||||||
// for the one currently-executing thread.
|
// for the one currently-executing thread.
|
||||||
//
|
//
|
||||||
Schedule thread_sched_;
|
Schedule thread_sched_;
|
||||||
|
|||||||
@@ -17,8 +17,12 @@ end
|
|||||||
|
|
||||||
function player.action.east(actor, place, gui)
|
function player.action.east(actor, place, gui)
|
||||||
print("Moving east")
|
print("Moving east")
|
||||||
|
t = nil
|
||||||
|
t[3] = 4
|
||||||
end
|
end
|
||||||
|
|
||||||
function player.action.west(actor, place, gui)
|
function player.action.west(actor, place, gui)
|
||||||
print("Moving west")
|
print("Moving west")
|
||||||
|
wait(0)
|
||||||
|
print("Moving west again")
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user