Implement stacktrace collecting (#95)
This commit is contained in:
parent
e84fbb32f4
commit
1df5e73f49
@ -11,14 +11,14 @@ std::string luaError(int errCode) {
|
||||
case LUA_ERRRUN: return "Execution error (LUA_ERRRUN)";
|
||||
case LUA_ERRGCMM: return "Error in __gc method (LUA_ERRGCMM)";
|
||||
case LUA_ERRERR: return "Recursive error (LUA_ERRERR)";
|
||||
default: return "Unknown";
|
||||
default: return "Unknown (" + std::to_string(errCode) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
int dumpMemoryWriter(lua_State*, const void* batch, size_t batchSize, void* storage) {
|
||||
if (storage == nullptr || batch == nullptr)
|
||||
if (storage == nullptr)
|
||||
return 1;
|
||||
if (batchSize) {
|
||||
if (batchSize && batch) {
|
||||
std::string& buff = *reinterpret_cast<std::string*>(storage);
|
||||
const char* newData = reinterpret_cast<const char*>(batch);
|
||||
buff.insert(buff.end(), newData, newData + batchSize);
|
||||
|
||||
@ -164,7 +164,7 @@ StoredObject fromSolObject(const SolObject& luaObject) {
|
||||
else if (luaObject.template is<Thread>())
|
||||
return std::make_unique<GCObjectHolder<Thread>>(luaObject);
|
||||
else
|
||||
throw Exception() << "Unable to store userdata object\n";
|
||||
throw Exception() << "Unable to store userdata object";
|
||||
case sol::type::function: {
|
||||
FunctionObject func = GC::instance().create<FunctionObject>(luaObject);
|
||||
return std::make_unique<FunctionHolder>(func.handle());
|
||||
|
||||
@ -51,14 +51,26 @@ enum class Command {
|
||||
Pause
|
||||
};
|
||||
|
||||
#if LUA_VERSION_NUM > 501
|
||||
|
||||
int luaErrorHandler(lua_State* state);
|
||||
const lua_CFunction luaErrorHandlerPtr = luaErrorHandler;
|
||||
|
||||
#else
|
||||
|
||||
const lua_CFunction luaErrorHandlerPtr = nullptr;
|
||||
|
||||
#endif // LUA_VERSION_NUM > 501
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
class ThreadHandle {
|
||||
public:
|
||||
ThreadHandle()
|
||||
: status_(Status::Running)
|
||||
, command_(Command::Run)
|
||||
, lua_(std::make_unique<sol::state>()) {
|
||||
, lua_(std::make_unique<sol::state>(luaErrorHandlerPtr)) {
|
||||
luaL_openlibs(*lua_);
|
||||
}
|
||||
|
||||
@ -141,6 +153,17 @@ const sol::optional<std::chrono::milliseconds> NO_TIMEOUT;
|
||||
|
||||
static thread_local ThreadHandle* thisThreadHandle = nullptr;
|
||||
|
||||
#if LUA_VERSION_NUM > 501
|
||||
|
||||
int luaErrorHandler(lua_State* state) {
|
||||
luaL_traceback(state, state, nullptr, 1);
|
||||
const auto stacktrace = sol::stack::pop<std::string>(state);
|
||||
thisThreadHandle->result().emplace_back(createStoredObject(stacktrace));
|
||||
throw Exception() << sol::stack::pop<std::string>(state);
|
||||
}
|
||||
|
||||
#endif // LUA_VERSION_NUM > 501
|
||||
|
||||
void luaHook(lua_State*, lua_Debug*) {
|
||||
assert(thisThreadHandle);
|
||||
switch (thisThreadHandle->command()) {
|
||||
@ -198,7 +221,10 @@ void Thread::runThread(Thread thread,
|
||||
thread.handle_->changeStatus(Status::Canceled);
|
||||
} catch (const sol::error& err) {
|
||||
DEBUG << "Failed with msg: " << err.what() << std::endl;
|
||||
thread.handle_->result().emplace_back(createStoredObject(err.what()));
|
||||
auto& returns = thread.handle_->result();
|
||||
returns.insert(returns.begin(),
|
||||
{ createStoredObject("failed"),
|
||||
createStoredObject(err.what()) });
|
||||
thread.handle_->changeStatus(Status::Failed);
|
||||
}
|
||||
}
|
||||
@ -279,14 +305,14 @@ void Thread::exportAPI(sol::state_view& lua) {
|
||||
sol::stack::pop<sol::object>(lua);
|
||||
}
|
||||
|
||||
std::pair<sol::object, sol::object> Thread::status(const sol::this_state& lua) {
|
||||
sol::object luaStatus = sol::make_object(lua, statusToString(handle_->status()));
|
||||
|
||||
if (handle_->status() == Status::Failed) {
|
||||
StoredArray Thread::status(const sol::this_state& lua) {
|
||||
const auto stat = handle_->status();
|
||||
if (stat == Status::Failed) {
|
||||
assert(!handle_->result().empty());
|
||||
return std::make_pair(luaStatus, handle_->result()[0]->unpack(lua));
|
||||
return handle_->result();
|
||||
} else {
|
||||
return std::make_pair(luaStatus, sol::nil);
|
||||
const sol::object luaStatus = sol::make_object(lua, statusToString(stat));
|
||||
return StoredArray({createStoredObject(luaStatus)});
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,7 +324,7 @@ sol::optional<std::chrono::milliseconds> toOptionalTime(const sol::optional<int>
|
||||
return sol::optional<std::chrono::milliseconds>();
|
||||
}
|
||||
|
||||
std::pair<sol::object, sol::object> Thread::wait(const sol::this_state& lua,
|
||||
StoredArray Thread::wait(const sol::this_state& lua,
|
||||
const sol::optional<int>& duration,
|
||||
const sol::optional<std::string>& period) {
|
||||
handle_->waitForCompletion(toOptionalTime(duration, period));
|
||||
|
||||
@ -23,10 +23,10 @@ public:
|
||||
|
||||
static void exportAPI(sol::state_view& lua);
|
||||
|
||||
std::pair<sol::object, sol::object> status(const sol::this_state& state);
|
||||
std::pair<sol::object, sol::object> wait(const sol::this_state& state,
|
||||
const sol::optional<int>& duration,
|
||||
const sol::optional<std::string>& period);
|
||||
StoredArray status(const sol::this_state& state);
|
||||
StoredArray wait(const sol::this_state& state,
|
||||
const sol::optional<int>& duration,
|
||||
const sol::optional<std::string>& period);
|
||||
StoredArray get(const sol::optional<int>& duration,
|
||||
const sol::optional<std::string>& period);
|
||||
bool cancel(const sol::this_state& state,
|
||||
|
||||
@ -370,3 +370,37 @@ test.this_thread.pause_on_finished_thread = function ()
|
||||
test.is_true(worker_thread:get(2, "s"))
|
||||
test.is_true(effil.thread(call_pause)(worker_thread):get(5, "s"))
|
||||
end
|
||||
|
||||
if LUA_VERSION > 51 then
|
||||
|
||||
test.thread.traceback = function()
|
||||
local curr_file = debug.getinfo(1,'S').short_src
|
||||
|
||||
local function foo()
|
||||
function boom()
|
||||
error("err msg")
|
||||
end
|
||||
function bar()
|
||||
boom()
|
||||
end
|
||||
bar()
|
||||
end
|
||||
|
||||
local status, err, trace = effil.thread(foo)():wait()
|
||||
print("status: ", status)
|
||||
print("error: ", err)
|
||||
print("stacktrace: ", trace)
|
||||
|
||||
test.equal(status, "failed")
|
||||
-- <souce file>.lua:<string number>: <error message>
|
||||
test.is_not_nil(string.find(err, curr_file .. ":%d+: err msg"))
|
||||
test.is_not_nil(string.find(trace, (
|
||||
[[stack traceback:
|
||||
%%s%s:%%d+: in function 'boom'
|
||||
%%s%s:%%d+: in function 'bar'
|
||||
%%s%s:%%d+: in function <%s:%%d+>]]
|
||||
):format(curr_file, curr_file, curr_file, curr_file)
|
||||
))
|
||||
end
|
||||
|
||||
end -- LUA_VERSION > 51
|
||||
Loading…
x
Reference in New Issue
Block a user