From 996ca25a2e596770212b7b7f5f5d851e13a022ec Mon Sep 17 00:00:00 2001 From: zhupengfei Date: Mon, 8 Feb 2021 11:24:05 +0800 Subject: [PATCH] core_timing: Lock CoreTiming event queue while deserializing To handle those classic asymmetric constructor/destructor side effects --- src/core/core.cpp | 1 + src/core/core_timing.cpp | 10 ++++++++++ src/core/core_timing.h | 12 ++++++++++++ 3 files changed, 23 insertions(+) diff --git a/src/core/core.cpp b/src/core/core.cpp index 0d7b58e2c..f1d5c7b00 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -629,6 +629,7 @@ void System::serialize(Archive& ar, const unsigned int file_version) { // This needs to be set from somewhere - might as well be here! if (Archive::is_loading::value) { + timing->UnlockEventQueue(); Service::GSP::SetGlobalModule(*this); memory->SetDSP(*dsp_core); cheat_engine->Connect(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 3d77932b6..4aa6d870e 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -49,6 +49,10 @@ TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback ca void Timing::ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_type, u64 userdata, std::size_t core_id) { + if (event_queue_locked) { + return; + } + ASSERT(event_type != nullptr); Timing::Timer* timer = nullptr; if (core_id == std::numeric_limits::max()) { @@ -74,6 +78,9 @@ void Timing::ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_ } void Timing::UnscheduleEvent(const TimingEventType* event_type, u64 userdata) { + if (event_queue_locked) { + return; + } for (auto timer : timers) { auto itr = std::remove_if( timer->event_queue.begin(), timer->event_queue.end(), @@ -89,6 +96,9 @@ void Timing::UnscheduleEvent(const TimingEventType* event_type, u64 userdata) { } void Timing::RemoveEvent(const TimingEventType* event_type) { + if (event_queue_locked) { + return; + } for (auto timer : timers) { auto itr = std::remove_if(timer->event_queue.begin(), timer->event_queue.end(), [&](const Event& e) { return e.type == event_type; }); diff --git a/src/core/core_timing.h b/src/core/core_timing.h index aebe5c742..611122211 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -280,6 +280,11 @@ public: std::shared_ptr GetTimer(std::size_t cpu_id); + // Used after deserializing to unprotect the event queue. + void UnlockEventQueue() { + event_queue_locked = false; + } + private: // unordered_map stores each element separately as a linked list node so pointers to // elements remain stable regardless of rehashes/resizing. @@ -292,6 +297,10 @@ private: // under/overclocking the guest cpu double cpu_clock_scale = 1.0; + // When true, the event queue can't be modified. Used while deserializing to workaround + // destructor side effects. + bool event_queue_locked = false; + template void serialize(Archive& ar, const unsigned int file_version) { // event_types set during initialization of other things @@ -303,6 +312,9 @@ private: } else { ar& current_timer; } + if (Archive::is_loading::value) { + event_queue_locked = true; + } } friend class boost::serialization::access; };