mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-07-13 02:03:44 +00:00
fix lua result serialization causing various issues
for example, loading a library which returns a table of functions would fail with an inexplicable (to the user) error about serialization. This is now fixed. We no longer use a single result type, instead there are void results and normal results, and the former simply never has to worry about the result. This was likely causing even more issues; if the `sol::object` was populated before, it hitting the dtor in another path would, again, like we've seen before, corrupt the lua stack.
This commit is contained in:
+47
-16
@@ -37,19 +37,54 @@ struct TDetachedLuaValue {
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, const TDetachedLuaValue& value);
|
||||
|
||||
struct TLuaResult {
|
||||
/// Result for operations that stay within one Lua state (e.g. script loads).
|
||||
/// This type intentionally does not store any Lua references or serialized Lua values.
|
||||
struct TLuaVoidResult {
|
||||
struct Snapshot {
|
||||
bool Error;
|
||||
bool Ready;
|
||||
std::string ErrorMessage;
|
||||
/// CAUTION: Accessing this object causes the Lua stack of the owning state
|
||||
/// to be accessed. Only call this from the owning Lua state. Otherwise,
|
||||
/// use `DetachedSnapshot`.
|
||||
sol::object Result;
|
||||
TLuaStateId StateId;
|
||||
std::string Function;
|
||||
};
|
||||
|
||||
explicit TLuaVoidResult(TLuaStateId StateId)
|
||||
: mStateId(std::move(StateId)) {}
|
||||
|
||||
/// Marks this result as success & sets it as ready, waking all waiting threads.
|
||||
void MarkReadySuccess();
|
||||
/// Marks this result as erroneous & sets it as ready, waking all waiting threads.
|
||||
void MarkReadyError(sol::protected_function_result Res);
|
||||
/// Marks this result as erroneous & sets it as ready, waking all waiting threads.
|
||||
void MarkReadyError(std::string Res);
|
||||
/// Wait (suspend) until this result is ready.
|
||||
void WaitUntilReady();
|
||||
bool IsReady() const;
|
||||
bool IsError() const;
|
||||
Snapshot GetSnapshot() const;
|
||||
|
||||
private:
|
||||
mutable std::mutex mMutex {};
|
||||
bool mReady { false };
|
||||
bool mError { false };
|
||||
std::string mErrorMessage;
|
||||
TLuaStateId mStateId;
|
||||
std::condition_variable mReadyCondition {};
|
||||
|
||||
void SetErrorMessageFromResult(sol::protected_function_result& Res) {
|
||||
if (Res.valid()) {
|
||||
beammp_lua_errorf("Error was not an error");
|
||||
}
|
||||
if (Res.get_type() == sol::type::string) {
|
||||
mErrorMessage = Res.get<sol::error>().what();
|
||||
} else {
|
||||
mErrorMessage = "(unknown error; error object is not inspectable)";
|
||||
}
|
||||
}
|
||||
|
||||
void MarkAsReady();
|
||||
};
|
||||
|
||||
struct TLuaResult {
|
||||
struct DetachedSnapshot {
|
||||
bool Error;
|
||||
bool Ready;
|
||||
@@ -66,33 +101,29 @@ struct TLuaResult {
|
||||
|
||||
/// Marks this result as success & sets it as ready, waking all threads waiting on it.
|
||||
void MarkReadySuccess(sol::object Res);
|
||||
/// Marks this result as successful and ready without serializing a Lua value.
|
||||
void MarkReadySuccessNoResult();
|
||||
/// Marks this result as erroneous & sets it as ready, waking all threads waiting on it.
|
||||
void MarkReadyError(sol::protected_function_result Res);
|
||||
/// Marks this result as erroneous & sets it as ready, waking all threads waiting on it.
|
||||
void MarkReadyError(std::string Res);
|
||||
/// Wait (suspend) until this result is ready. Use `GetSnapshot` to get the results.
|
||||
/// Wait (suspend) until this result is ready. Use `GetDetachedSnapshot` to get the result.
|
||||
void WaitUntilReady();
|
||||
bool IsReady() const;
|
||||
bool IsError() const;
|
||||
TLuaStateId OwnerState() const;
|
||||
void SetOwnerState(TLuaStateId StateId);
|
||||
|
||||
/// To get the result or error, while in the owning state, use this function.
|
||||
/// Pass your lua state ID so that the function can verify the safety of the access.
|
||||
/// If you have no state ID, use `GetDetachedSnapshot`.
|
||||
/// Accesses the Lua state directly when using the result.
|
||||
Snapshot GetSnapshot(TLuaStateId CallingState) const;
|
||||
/// Returns a snapshot with, if not an error, a serialized version of the result
|
||||
/// object. In contrast to `GetSnapshot`, this does not access the Lua stack when
|
||||
/// accessing `.Result`.
|
||||
/// object. This never stores or returns raw Lua references and is safe to use
|
||||
/// across threads.
|
||||
DetachedSnapshot GetDetachedSnapshot() const;
|
||||
|
||||
private:
|
||||
mutable std::mutex mMutex {};
|
||||
bool mReady { false };
|
||||
bool mError;
|
||||
bool mError { false };
|
||||
std::string mErrorMessage;
|
||||
sol::object mResult { sol::lua_nil };
|
||||
TDetachedLuaValue mDetachedResult;
|
||||
TLuaStateId mStateId;
|
||||
std::string mFunction;
|
||||
|
||||
Reference in New Issue
Block a user