summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorJules Blok <jules.blok@gmail.com>2014-06-20 02:43:57 +0200
committerJules Blok <jules.blok@gmail.com>2014-07-08 21:21:23 +0200
commit3266394dfbb564f69e3cd6470ad608a4db314916 (patch)
treec867e081920c9c8c31fbe7bc0e47ca8c6aa2d3ec /Source/Core
parentff6fa68b71989bbc528654dca3b7d541fedc05f6 (diff)
Make the emulation stop asynchronous to prevent deadlocks.
This may expose bugs which relied on the Main Thread to be suspended in the stopping state.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Core.cpp75
-rw-r--r--Source/Core/Core/Core.h5
-rw-r--r--Source/Core/DolphinWX/Frame.cpp15
-rw-r--r--Source/Core/DolphinWX/Frame.h2
-rw-r--r--Source/Core/DolphinWX/FrameTools.cpp105
-rw-r--r--Source/Core/DolphinWX/Globals.h1
-rw-r--r--Source/Core/DolphinWX/Main.cpp2
7 files changed, 125 insertions, 80 deletions
diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp
index 3fffedb7fb..245b489663 100644
--- a/Source/Core/Core/Core.cpp
+++ b/Source/Core/Core/Core.cpp
@@ -83,6 +83,7 @@ bool g_bStarted = false;
void *g_pWindowHandle = nullptr;
std::string g_stateFileName;
std::thread g_EmuThread;
+static StoppedCallbackFunc s_onStoppedCb = nullptr;
static std::thread g_cpu_thread;
static bool g_requestRefreshInfo = false;
@@ -155,7 +156,7 @@ bool IsRunning()
bool IsRunningAndStarted()
{
- return g_bStarted;
+ return g_bStarted && !g_bStopping;
}
bool IsRunningInCurrentThread()
@@ -191,8 +192,14 @@ bool Init()
if (g_EmuThread.joinable())
{
- PanicAlertT("Emu Thread already running");
- return false;
+ if (IsRunning())
+ {
+ PanicAlertT("Emu Thread already running");
+ return false;
+ }
+
+ // The Emu Thread was stopped, synchronize with it.
+ g_EmuThread.join();
}
g_CoreStartupParameter = _CoreParameter;
@@ -226,12 +233,8 @@ bool Init()
// Called from GUI thread
void Stop() // - Hammertime!
{
- if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
- {
- if (g_EmuThread.joinable())
- g_EmuThread.join();
+ if (GetState() == CORE_STOPPING)
return;
- }
const SCoreStartupParameter& _CoreParameter =
SConfig::GetInstance().m_LocalCoreStartupParameter;
@@ -258,28 +261,6 @@ void Stop() // - Hammertime!
g_video_backend->Video_ExitLoop();
}
-
- INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str());
-
- g_EmuThread.join(); // Wait for emuthread to close.
-
- INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str());
-
- // Clear on screen messages that haven't expired
- g_video_backend->Video_ClearMessages();
-
- // Close the trace file
- Core::StopTrace();
-
- // Reload sysconf file in order to see changes committed during emulation
- if (_CoreParameter.bWii)
- SConfig::GetInstance().m_SYSCONF->Reload();
-
- INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----");
- Movie::Shutdown();
- PatchEngine::Shutdown();
-
- g_bStopping = false;
}
// Create the CPU thread, which is a CPU + Video thread in Single Core mode.
@@ -478,6 +459,8 @@ void EmuThread()
}
}
+ INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str());
+
// Wait for g_cpu_thread to exit
INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str());
@@ -510,6 +493,27 @@ void EmuThread()
Wiimote::Shutdown();
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
+ g_video_backend->Video_ClearMessages();
+
+ // Close the trace file
+ Core::StopTrace();
+
+ // Reload sysconf file in order to see changes committed during emulation
+ if (_CoreParameter.bWii)
+ SConfig::GetInstance().m_SYSCONF->Reload();
+
+ INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----");
+ Movie::Shutdown();
+ PatchEngine::Shutdown();
+
+ g_bStopping = false;
+
+ if (s_onStoppedCb)
+ s_onStoppedCb();
}
// Set or get the running state
@@ -740,4 +744,15 @@ void UpdateTitle()
}
}
+void Shutdown()
+{
+ if (g_EmuThread.joinable())
+ g_EmuThread.join();
+}
+
+void SetOnStoppedCallback(StoppedCallbackFunc callback)
+{
+ s_onStoppedCb = callback;
+}
+
} // Core
diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h
index 862160daf0..655c5f9301 100644
--- a/Source/Core/Core/Core.h
+++ b/Source/Core/Core/Core.h
@@ -39,6 +39,7 @@ enum EState
bool Init();
void Stop();
+void Shutdown();
std::string StopMessage(bool, std::string);
@@ -81,4 +82,8 @@ void UpdateTitle();
// the return value of the first call should be passed in as the second argument of the second call.
bool PauseAndLock(bool doLock, bool unpauseOnUnlock=true);
+// for calling back into UI code without introducing a dependency on it in core
+typedef void(*StoppedCallbackFunc)(void);
+void SetOnStoppedCallback(StoppedCallbackFunc callback);
+
} // namespace
diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp
index 5284eefd57..1807c5e53b 100644
--- a/Source/Core/DolphinWX/Frame.cpp
+++ b/Source/Core/DolphinWX/Frame.cpp
@@ -425,6 +425,7 @@ CFrame::CFrame(wxFrame* parent,
Movie::SetInputManip(TASManipFunction);
State::SetOnAfterLoadCallback(OnAfterLoadCallback);
+ Core::SetOnStoppedCallback(OnStoppedCallback);
// Setup perspectives
if (g_pCodeWindow)
@@ -692,6 +693,10 @@ void CFrame::OnHostMessage(wxCommandEvent& event)
case WM_USER_STOP:
DoStop();
break;
+
+ case IDM_STOPPED:
+ OnStopped();
+ break;
}
}
@@ -904,6 +909,16 @@ void OnAfterLoadCallback()
}
}
+void OnStoppedCallback()
+{
+ // warning: this gets called from the EmuThread, so we should only queue things to do on the proper thread
+ if (main_frame)
+ {
+ wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_STOPPED);
+ main_frame->GetEventHandler()->AddPendingEvent(event);
+ }
+}
+
void TASManipFunction(SPADStatus *PadStatus, int controllerID)
{
if (main_frame)
diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h
index 32292c1cb4..e32b91f918 100644
--- a/Source/Core/DolphinWX/Frame.h
+++ b/Source/Core/DolphinWX/Frame.h
@@ -123,6 +123,7 @@ public:
void InitBitmaps();
void DoPause();
void DoStop();
+ void OnStopped();
void DoRecordingSave();
void UpdateGUI();
void UpdateGameList();
@@ -353,6 +354,7 @@ private:
int GetCmdForHotkey(unsigned int key);
void OnAfterLoadCallback();
+void OnStoppedCallback();
// For TASInputDlg
void TASManipFunction(SPADStatus *PadStatus, int controllerID);
diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp
index 6548deb5f0..7c72aad691 100644
--- a/Source/Core/DolphinWX/FrameTools.cpp
+++ b/Source/Core/DolphinWX/FrameTools.cpp
@@ -1120,72 +1120,77 @@ void CFrame::DoStop()
wxBeginBusyCursor();
BootManager::Stop();
- wxEndBusyCursor();
- confirmStop = false;
+ }
+}
+
+void CFrame::OnStopped()
+{
+ wxEndBusyCursor();
+
+ confirmStop = false;
#if defined(HAVE_X11) && HAVE_X11
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bDisableScreenSaver)
X11Utils::InhibitScreensaver(X11Utils::XDisplayFromHandle(GetHandle()),
X11Utils::XWindowFromHandle(GetHandle()), false);
#endif
- m_RenderFrame->SetTitle(StrToWxStr(scm_rev_str));
+ m_RenderFrame->SetTitle(StrToWxStr(scm_rev_str));
- // Destroy the renderer frame when not rendering to main
- m_RenderParent->Unbind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this);
-
- // Keyboard
- wxTheApp->Unbind(wxEVT_KEY_DOWN, &CFrame::OnKeyDown, this);
- wxTheApp->Unbind(wxEVT_KEY_UP, &CFrame::OnKeyUp, this);
-
- // Mouse
- wxTheApp->Unbind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this);
- wxTheApp->Unbind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this);
- wxTheApp->Unbind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this);
- wxTheApp->Unbind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this);
- wxTheApp->Unbind(wxEVT_MOTION, &CFrame::OnMouse, this);
- if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
- m_RenderParent->SetCursor(wxNullCursor);
- DoFullscreen(false);
- if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain)
- {
- m_RenderFrame->Destroy();
- }
- else
- {
+ // Destroy the renderer frame when not rendering to main
+ m_RenderParent->Unbind(wxEVT_SIZE, &CFrame::OnRenderParentResize, this);
+
+ // Keyboard
+ wxTheApp->Unbind(wxEVT_KEY_DOWN, &CFrame::OnKeyDown, this);
+ wxTheApp->Unbind(wxEVT_KEY_UP, &CFrame::OnKeyUp, this);
+
+ // Mouse
+ wxTheApp->Unbind(wxEVT_RIGHT_DOWN, &CFrame::OnMouse, this);
+ wxTheApp->Unbind(wxEVT_RIGHT_UP, &CFrame::OnMouse, this);
+ wxTheApp->Unbind(wxEVT_MIDDLE_DOWN, &CFrame::OnMouse, this);
+ wxTheApp->Unbind(wxEVT_MIDDLE_UP, &CFrame::OnMouse, this);
+ wxTheApp->Unbind(wxEVT_MOTION, &CFrame::OnMouse, this);
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)
+ m_RenderParent->SetCursor(wxNullCursor);
+ DoFullscreen(false);
+ if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain)
+ {
+ m_RenderFrame->Destroy();
+ }
+ else
+ {
#if defined(__APPLE__)
- // Disable the full screen button when not in a game.
- NSView *view = (NSView *) m_RenderFrame->GetHandle();
- NSWindow *window = [view window];
+ // Disable the full screen button when not in a game.
+ NSView *view = (NSView *)m_RenderFrame->GetHandle();
+ NSWindow *window = [view window];
- [window setCollectionBehavior:NSWindowCollectionBehaviorDefault];
+ [window setCollectionBehavior : NSWindowCollectionBehaviorDefault];
#endif
- // Make sure the window is not longer set to stay on top
- m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP);
- }
- m_RenderParent = nullptr;
+ // Make sure the window is not longer set to stay on top
+ m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP);
+ }
+ m_RenderParent = nullptr;
- // Clean framerate indications from the status bar.
- GetStatusBar()->SetStatusText(" ", 0);
+ // Clean framerate indications from the status bar.
+ GetStatusBar()->SetStatusText(" ", 0);
- // Clear wiimote connection status from the status bar.
- GetStatusBar()->SetStatusText(" ", 1);
+ // Clear wiimote connection status from the status bar.
+ GetStatusBar()->SetStatusText(" ", 1);
- // If batch mode was specified on the command-line, exit now.
- if (m_bBatchMode)
- Close(true);
+ // If batch mode was specified on the command-line, exit now.
+ if (m_bBatchMode)
+ Close(true);
- // If using auto size with render to main, reset the application size.
- if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain &&
- SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderWindowAutoSize)
- SetSize(SConfig::GetInstance().m_LocalCoreStartupParameter.iWidth,
- SConfig::GetInstance().m_LocalCoreStartupParameter.iHeight);
+ // If using auto size with render to main, reset the application size.
+ if (SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain &&
+ SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderWindowAutoSize)
+ SetSize(SConfig::GetInstance().m_LocalCoreStartupParameter.iWidth,
+ SConfig::GetInstance().m_LocalCoreStartupParameter.iHeight);
- m_GameListCtrl->Enable();
- m_GameListCtrl->Show();
- m_GameListCtrl->SetFocus();
- UpdateGUI();
- }
+ m_GameListCtrl->Enable();
+ m_GameListCtrl->Show();
+ m_GameListCtrl->SetFocus();
+ UpdateGUI();
}
void CFrame::DoRecordingSave()
diff --git a/Source/Core/DolphinWX/Globals.h b/Source/Core/DolphinWX/Globals.h
index d51ee2c135..401f4265ad 100644
--- a/Source/Core/DolphinWX/Globals.h
+++ b/Source/Core/DolphinWX/Globals.h
@@ -254,6 +254,7 @@ enum
IDM_PANIC,
IDM_KEYSTATE,
IDM_WINDOWSIZEREQUEST,
+ IDM_STOPPED,
IDM_HOST_MESSAGE,
IDM_MPANEL, ID_STATUSBAR,
diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp
index 3643d6e5ec..0559e9b7bf 100644
--- a/Source/Core/DolphinWX/Main.cpp
+++ b/Source/Core/DolphinWX/Main.cpp
@@ -37,6 +37,7 @@
#include "Common/Logging/LogManager.h"
#include "Core/ConfigManager.h"
+#include "Core/Core.h"
#include "Core/CoreParameter.h"
#include "Core/Movie.h"
#include "Core/HW/Wiimote.h"
@@ -455,6 +456,7 @@ int DolphinApp::OnExit()
VideoBackend::ClearList();
SConfig::Shutdown();
LogManager::Shutdown();
+ Core::Shutdown();
delete m_locale;