From e602eac4f962c6c9e9f57b04be5f0cee57236f75 Mon Sep 17 00:00:00 2001 From: comex Date: Sat, 6 Jun 2015 01:41:26 -0400 Subject: [PATCH] Synchronize DVDInterface::ChangeDisc with the CPU thread properly. This addresses a bit of thread unsafety mentioned in a comment, and fixes a 'ScheduleEvent_Threadsafe from main thread' message. To make this work nicely, make PauseAndLock call DeclareAsCPUThread - i.e. while you have the CPU thread locked, you can consider yourself the CPU thread. --- Source/Core/Core/Core.cpp | 5 +++-- Source/Core/Core/Core.h | 3 +++ Source/Core/Core/HW/CPU.cpp | 15 ++++++++++++++- Source/Core/Core/HW/DVDInterface.cpp | 10 +++++++--- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 61e1f14be5..844801a0ca 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -276,7 +276,7 @@ void Stop() // - Hammertime! } } -static void DeclareAsCPUThread() +void DeclareAsCPUThread() { #ifdef ThreadLocalStorage tls_is_cpu_thread = true; @@ -288,7 +288,7 @@ static void DeclareAsCPUThread() #endif } -static void UndeclareAsCPUThread() +void UndeclareAsCPUThread() { #ifdef ThreadLocalStorage tls_is_cpu_thread = false; @@ -715,6 +715,7 @@ bool PauseAndLock(bool doLock, bool unpauseOnUnlock) // video has to come after CPU, because CPU thread can wait for video thread (s_efbAccessRequested). g_video_backend->PauseAndLock(doLock, unpauseOnUnlock); + return wasUnpaused; } diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index 76015a44b1..8389f9e308 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -41,6 +41,9 @@ bool Init(); void Stop(); void Shutdown(); +void DeclareAsCPUThread(); +void UndeclareAsCPUThread(); + std::string StopMessage(bool, const std::string&); bool IsRunning(); diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp index 96eb937054..54971cdd89 100644 --- a/Source/Core/Core/HW/CPU.cpp +++ b/Source/Core/Core/HW/CPU.cpp @@ -149,13 +149,22 @@ void Break() bool PauseAndLock(bool do_lock, bool unpause_on_unlock) { + static bool s_have_fake_cpu_thread; bool wasUnpaused = !IsStepping(); if (do_lock) { // we can't use EnableStepping, that would causes deadlocks with both audio and video PowerPC::Pause(); if (!Core::IsCPUThread()) + { m_csCpuOccupied.lock(); + s_have_fake_cpu_thread = true; + Core::DeclareAsCPUThread(); + } + else + { + s_have_fake_cpu_thread = false; + } } else { @@ -165,8 +174,12 @@ bool PauseAndLock(bool do_lock, bool unpause_on_unlock) m_StepEvent.Set(); } - if (!Core::IsCPUThread()) + if (s_have_fake_cpu_thread) + { + Core::UndeclareAsCPUThread(); m_csCpuOccupied.unlock(); + s_have_fake_cpu_thread = false; + } } return wasUnpaused; } diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index 46219fb606..e0356ec12a 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -14,6 +14,7 @@ #include "Common/MathUtil.h" #include "Core/ConfigManager.h" +#include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/Movie.h" #include "Core/HW/AudioInterface.h" @@ -522,10 +523,11 @@ void InsertDiscCallback(u64 userdata, int cyclesLate) void ChangeDisc(const std::string& newFileName) { + bool is_cpu = Core::IsCPUThread(); + bool was_unpaused = is_cpu ? false : Core::PauseAndLock(true); std::string* _FileName = new std::string(newFileName); - CoreTiming::ScheduleEvent_Threadsafe(0, ejectDisc); - CoreTiming::ScheduleEvent_Threadsafe(500000000, insertDisc, (u64)_FileName); - // TODO: We shouldn't be modifying movie state from the GUI thread. + CoreTiming::ScheduleEvent(0, ejectDisc); + CoreTiming::ScheduleEvent(500000000, insertDisc, (u64)_FileName); if (Movie::IsRecordingInput()) { Movie::g_bDiscChange = true; @@ -538,6 +540,8 @@ void ChangeDisc(const std::string& newFileName) } Movie::g_discChange = fileName.substr(sizeofpath); } + if (!is_cpu) + Core::PauseAndLock(false, was_unpaused); } void SetLidOpen(bool _bOpen)