From 52f00603e217faad8f21f4b4daf2713967546878 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 27 May 2017 18:48:40 +0200 Subject: [PATCH 1/2] Core: Use RAII for EmuThread shutdown This is more reliable, as this guarantees subsystems will be shut down in the same order they were initialised (if they were initialised). It also allows us to stop keeping track of what needs to be shut down manually and just return in case of errors. This should prevent the emulator from getting totally stuck when the boot process does fail. --- Source/Core/Core/Core.cpp | 69 ++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 60db83c98f..122289c5b0 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -24,6 +24,7 @@ #include "Common/Logging/LogManager.h" #include "Common/MemoryUtil.h" #include "Common/MsgHandler.h" +#include "Common/ScopeGuard.h" #include "Common/StringUtil.h" #include "Common/Thread.h" #include "Common/Timer.h" @@ -453,6 +454,19 @@ static void EmuThread() { const SConfig& core_parameter = SConfig::GetInstance(); s_is_booting.Set(); + Common::ScopeGuard flag_guard{[] { + s_is_booting.Clear(); + s_is_started = false; + s_is_stopping = false; + + if (s_on_stopped_callback) + s_on_stopped_callback(); + + INFO_LOG(CONSOLE, "Stop\t\t---- Shutdown complete ----"); + }}; + + // Prevent the UI from getting stuck whenever an error occurs. + Common::ScopeGuard stop_message_guard{[] { Host_Message(WM_USER_STOP); }}; Common::SetCurrentThreadName("Emuthread - Starting"); @@ -466,16 +480,23 @@ static void EmuThread() DeclareAsCPUThread(); Movie::Init(); + Common::ScopeGuard movie_guard{Movie::Shutdown}; HW::Init(); + Common::ScopeGuard hw_guard{[] { + // We must set up this flag before executing HW::Shutdown() + s_hardware_initialized = false; + INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); + HW::Shutdown(); + INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str()); + }}; if (!g_video_backend->Initialize(s_window_handle)) { - s_is_booting.Clear(); PanicAlert("Failed to initialize video backend!"); - Host_Message(WM_USER_STOP); return; } + Common::ScopeGuard video_guard{[] { g_video_backend->Shutdown(); }}; OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000); @@ -486,11 +507,7 @@ static void EmuThread() if (!DSP::GetDSPEmulator()->Initialize(core_parameter.bWii, core_parameter.bDSPThread)) { - s_is_booting.Clear(); - HW::Shutdown(); - g_video_backend->Shutdown(); PanicAlert("Failed to initialize DSP emulation!"); - Host_Message(WM_USER_STOP); return; } @@ -520,7 +537,18 @@ static void EmuThread() Wiimote::LoadConfig(); } + Common::ScopeGuard controller_guard{[init_controllers] { + if (!init_controllers) + return; + + Wiimote::Shutdown(); + Keyboard::Shutdown(); + Pad::Shutdown(); + g_controller_interface.Shutdown(); + }}; + AudioCommon::InitSoundStream(); + Common::ScopeGuard audio_guard{AudioCommon::ShutdownSoundStream}; // The hardware is initialized. s_hardware_initialized = true; @@ -617,40 +645,15 @@ static void EmuThread() if (core_parameter.bCPUThread) g_video_backend->Video_Cleanup(); - // We must set up this flag before executing HW::Shutdown() - s_hardware_initialized = false; - INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); - HW::Shutdown(); - INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str()); - - if (init_controllers) - { - Wiimote::Shutdown(); - Keyboard::Shutdown(); - Pad::Shutdown(); - g_controller_interface.Shutdown(); - init_controllers = false; - } - - g_video_backend->Shutdown(); - AudioCommon::ShutdownSoundStream(); - - INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str()); - // Clear on screen messages that haven't expired OSD::ClearMessages(); BootManager::RestoreConfig(); - INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----"); - Movie::Shutdown(); PatchEngine::Shutdown(); HLE::Clear(); - - s_is_stopping = false; - - if (s_on_stopped_callback) - s_on_stopped_callback(); + // If we shut down normally, the stop message does not need to be triggered. + stop_message_guard.Dismiss(); } // Set or get the running state From 546181c4571ddf995fa5cad13596a254f1330491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 27 May 2017 18:57:07 +0200 Subject: [PATCH 2/2] WX: Clear m_is_game_loading at the proper moment This should happen after the core has stopped (OnStopped), not when the user wants to stop (DoStop). --- Source/Core/DolphinWX/FrameTools.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index 0ba143172f..b8e4e5fbf9 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -818,7 +818,6 @@ void CFrame::DoStop() // don't let this function run again until it finishes, or is aborted. m_confirm_stop = true; - m_is_game_loading = false; if (Core::GetState() != Core::State::Uninitialized || m_render_parent != nullptr) { #if defined __WXGTK__ @@ -919,6 +918,7 @@ bool CFrame::TriggerSTMPowerEvent() void CFrame::OnStopped() { m_confirm_stop = false; + m_is_game_loading = false; m_tried_graceful_shutdown = false; UninhibitScreensaver();