core_timing: Lock CoreTiming event queue while deserializing
To handle those classic asymmetric constructor/destructor side effects
This commit is contained in:
		| @@ -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(); | ||||
|   | ||||
| @@ -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<std::size_t>::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; }); | ||||
|   | ||||
| @@ -280,6 +280,11 @@ public: | ||||
|  | ||||
|     std::shared_ptr<Timer> 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 <class Archive> | ||||
|     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; | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user