summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar bunnei2015-04-28 19:03:01 -0400
committerGravatar bunnei2015-05-01 18:27:07 -0400
commite4ea133717a5292339c134160da984ba186d3de8 (patch)
treef6c3e289eaee3c79375d136279509523d4b3aca8
parentQt: Fix loading a new game without stopping emulation. (diff)
downloadyuzu-e4ea133717a5292339c134160da984ba186d3de8.tar.gz
yuzu-e4ea133717a5292339c134160da984ba186d3de8.tar.xz
yuzu-e4ea133717a5292339c134160da984ba186d3de8.zip
Qt: Restructured to remove unnecessary shutdown event and various cleanups.
Diffstat (limited to '')
-rw-r--r--src/citra_qt/bootmanager.cpp43
-rw-r--r--src/citra_qt/bootmanager.h44
-rw-r--r--src/citra_qt/debugger/disassembler.cpp10
-rw-r--r--src/citra_qt/main.cpp33
4 files changed, 40 insertions, 90 deletions
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index fa4e976f4..1e902a8b6 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -28,9 +28,8 @@
28#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" 28#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
29 29
30EmuThread::EmuThread(GRenderWindow* render_window) : 30EmuThread::EmuThread(GRenderWindow* render_window) :
31 exec_cpu_step(false), cpu_running(false), stop_run(false), render_window(render_window) { 31 exec_step(false), running(false), stop_run(false), render_window(render_window) {
32 32
33 shutdown_event.Reset();
34 connect(this, SIGNAL(started()), render_window, SLOT(moveContext())); 33 connect(this, SIGNAL(started()), render_window, SLOT(moveContext()));
35} 34}
36 35
@@ -42,20 +41,20 @@ void EmuThread::run() {
42 // next execution step 41 // next execution step
43 bool was_active = false; 42 bool was_active = false;
44 while (!stop_run) { 43 while (!stop_run) {
45 if (cpu_running) { 44 if (running) {
46 if (!was_active) 45 if (!was_active)
47 emit DebugModeLeft(); 46 emit DebugModeLeft();
48 47
49 Core::RunLoop(); 48 Core::RunLoop();
50 49
51 was_active = cpu_running || exec_cpu_step; 50 was_active = running || exec_step;
52 if (!was_active) 51 if (!was_active)
53 emit DebugModeEntered(); 52 emit DebugModeEntered();
54 } else if (exec_cpu_step) { 53 } else if (exec_step) {
55 if (!was_active) 54 if (!was_active)
56 emit DebugModeLeft(); 55 emit DebugModeLeft();
57 56
58 exec_cpu_step = false; 57 exec_step = false;
59 Core::SingleStep(); 58 Core::SingleStep();
60 emit DebugModeEntered(); 59 emit DebugModeEntered();
61 yieldCurrentThread(); 60 yieldCurrentThread();
@@ -65,40 +64,8 @@ void EmuThread::run() {
65 } 64 }
66 65
67 render_window->moveContext(); 66 render_window->moveContext();
68
69 shutdown_event.Set();
70} 67}
71 68
72void EmuThread::Stop() {
73 if (!isRunning()) {
74 LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning...");
75 return;
76 }
77 stop_run = true;
78
79 // Release emu threads from any breakpoints, so that this doesn't hang forever.
80 Pica::g_debug_context->ClearBreakpoints();
81
82 //core::g_state = core::SYS_DIE;
83
84 // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
85 wait(1000);
86 if (isRunning()) {
87 LOG_WARNING(Frontend, "EmuThread still running, terminating...");
88 quit();
89
90 // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
91 // queued... This should be fixed.
92 wait(50000);
93 if (isRunning()) {
94 LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here...");
95 terminate();
96 }
97 }
98 LOG_INFO(Frontend, "EmuThread stopped");
99}
100
101
102// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context. 69// This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
103// The corresponding functionality is handled in EmuThread instead 70// The corresponding functionality is handled in EmuThread instead
104class GGLWidgetInternal : public QGLWidget 71class GGLWidgetInternal : public QGLWidget
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index f6f09773c..e9b3ea664 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -25,66 +25,46 @@ public:
25 25
26 /** 26 /**
27 * Start emulation (on new thread) 27 * Start emulation (on new thread)
28 *
29 * @warning Only call when not running! 28 * @warning Only call when not running!
30 */ 29 */
31 void run() override; 30 void run() override;
32 31
33 /** 32 /**
34 * Allow the CPU to process a single instruction (if cpu is not running) 33 * Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
35 *
36 * @note This function is thread-safe 34 * @note This function is thread-safe
37 */ 35 */
38 void ExecStep() { exec_cpu_step = true; } 36 void ExecStep() { exec_step = true; }
39 37
40 /** 38 /**
41 * Sets whether the CPU is running 39 * Sets whether the emulation thread is running or not
42 * 40 * @param running Boolean value, set the emulation thread to running if true
43 * @note This function is thread-safe 41 * @note This function is thread-safe
44 */ 42 */
45 void SetCpuRunning(bool running) { cpu_running = running; } 43 void SetRunning(bool running) { this->running = running; }
46 44
47 /** 45 /**
48 * Allow the CPU to continue processing instructions without interruption 46 * Check if the emulation thread is running or not
49 * 47 * @return True if the emulation thread is running, otherwise false
50 * @note This function is thread-safe 48 * @note This function is thread-safe
51 */ 49 */
52 bool IsCpuRunning() { return cpu_running; } 50 bool IsRunning() { return running; }
53
54
55 /**
56 * Shutdown (permantently stops) the CPU
57 */
58 void ShutdownCpu() { stop_run = true; };
59 51
60 /** 52 /**
61 * Waits for the CPU shutdown to complete 53 * Shutdown (permanently stops) the emulation thread
62 */ 54 */
63 void WaitForCpuShutdown() { shutdown_event.Wait(); } 55 void Shutdown() { stop_run = true; };
64
65
66public slots:
67 /**
68 * Stop emulation and wait for the thread to finish.
69 *
70 * @details: This function will wait a second for the thread to finish; if it hasn't finished until then, we'll terminate() it and wait another second, hoping that it will be terminated by then.
71 * @note: This function is thread-safe.
72 */
73 void Stop();
74 56
75private: 57private:
76 friend class GMainWindow; 58 friend class GMainWindow;
77 59
78 EmuThread(GRenderWindow* render_window); 60 EmuThread(GRenderWindow* render_window);
79 61
80 bool exec_cpu_step; 62 bool exec_step;
81 bool cpu_running; 63 bool running;
82 std::atomic<bool> stop_run; 64 std::atomic<bool> stop_run;
83 65
84 GRenderWindow* render_window; 66 GRenderWindow* render_window;
85 67
86 Common::Event shutdown_event;
87
88signals: 68signals:
89 /** 69 /**
90 * Emitted when the CPU has halted execution 70 * Emitted when the CPU has halted execution
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index b58edafe7..f9423e1d6 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -201,7 +201,7 @@ void DisassemblerWidget::Init()
201 201
202void DisassemblerWidget::OnContinue() 202void DisassemblerWidget::OnContinue()
203{ 203{
204 main_window.GetEmuThread()->SetCpuRunning(true); 204 main_window.GetEmuThread()->SetRunning(true);
205} 205}
206 206
207void DisassemblerWidget::OnStep() 207void DisassemblerWidget::OnStep()
@@ -211,13 +211,13 @@ void DisassemblerWidget::OnStep()
211 211
212void DisassemblerWidget::OnStepInto() 212void DisassemblerWidget::OnStepInto()
213{ 213{
214 main_window.GetEmuThread()->SetCpuRunning(false); 214 main_window.GetEmuThread()->SetRunning(false);
215 main_window.GetEmuThread()->ExecStep(); 215 main_window.GetEmuThread()->ExecStep();
216} 216}
217 217
218void DisassemblerWidget::OnPause() 218void DisassemblerWidget::OnPause()
219{ 219{
220 main_window.GetEmuThread()->SetCpuRunning(false); 220 main_window.GetEmuThread()->SetRunning(false);
221 221
222 // TODO: By now, the CPU might not have actually stopped... 222 // TODO: By now, the CPU might not have actually stopped...
223 if (Core::g_app_core) { 223 if (Core::g_app_core) {
@@ -227,7 +227,7 @@ void DisassemblerWidget::OnPause()
227 227
228void DisassemblerWidget::OnToggleStartStop() 228void DisassemblerWidget::OnToggleStartStop()
229{ 229{
230 main_window.GetEmuThread()->SetCpuRunning(!main_window.GetEmuThread()->IsCpuRunning()); 230 main_window.GetEmuThread()->SetRunning(!main_window.GetEmuThread()->IsRunning());
231} 231}
232 232
233void DisassemblerWidget::OnDebugModeEntered() 233void DisassemblerWidget::OnDebugModeEntered()
@@ -235,7 +235,7 @@ void DisassemblerWidget::OnDebugModeEntered()
235 ARMword next_instr = Core::g_app_core->GetPC(); 235 ARMword next_instr = Core::g_app_core->GetPC();
236 236
237 if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) 237 if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
238 main_window.GetEmuThread()->SetCpuRunning(false); 238 main_window.GetEmuThread()->SetRunning(false);
239 239
240 model->SetNextInstruction(next_instr); 240 model->SetNextInstruction(next_instr);
241 241
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 5441c17f1..dd180baa4 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -199,10 +199,6 @@ void GMainWindow::OnDisplayTitleBars(bool show)
199void GMainWindow::BootGame(std::string filename) { 199void GMainWindow::BootGame(std::string filename) {
200 LOG_INFO(Frontend, "Citra starting...\n"); 200 LOG_INFO(Frontend, "Citra starting...\n");
201 201
202 // Shutdown previous session if the emu thread is still active...
203 if (emu_thread != nullptr)
204 ShutdownGame();
205
206 System::Init(render_window); 202 System::Init(render_window);
207 203
208 // Load a game or die... 204 // Load a game or die...
@@ -222,29 +218,36 @@ void GMainWindow::BootGame(std::string filename) {
222} 218}
223 219
224void GMainWindow::ShutdownGame() { 220void GMainWindow::ShutdownGame() {
225 emu_thread->SetCpuRunning(false); 221 // Shutdown the emulation thread and wait for it to complete
226 222 emu_thread->SetRunning(false);
227 emu_thread->ShutdownCpu(); 223 emu_thread->Shutdown();
228 emu_thread->WaitForCpuShutdown(); 224 emu_thread->wait();
229 emu_thread->Stop();
230
231 delete emu_thread; 225 delete emu_thread;
232 emu_thread = nullptr; 226 emu_thread = nullptr;
233 227
228 // Release emu threads from any breakpoints
229 Pica::g_debug_context->ClearBreakpoints();
230
231 // Shutdown the core emulation
234 System::Shutdown(); 232 System::Shutdown();
235 233
234 // Update the GUI
236 ui.action_Start->setEnabled(true); 235 ui.action_Start->setEnabled(true);
237 ui.action_Pause->setEnabled(false); 236 ui.action_Pause->setEnabled(false);
238 ui.action_Stop->setEnabled(false); 237 ui.action_Stop->setEnabled(false);
239
240 render_window->hide(); 238 render_window->hide();
241} 239}
242 240
243void GMainWindow::OnMenuLoadFile() 241void GMainWindow::OnMenuLoadFile()
244{ 242{
245 QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)")); 243 QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
246 if (filename.size()) 244 if (filename.size()) {
247 BootGame(filename.toLatin1().data()); 245 // Shutdown previous session if the emu thread is still active...
246 if (emu_thread != nullptr)
247 ShutdownGame();
248
249 BootGame(filename.toLatin1().data());
250 }
248} 251}
249 252
250void GMainWindow::OnMenuLoadSymbolMap() { 253void GMainWindow::OnMenuLoadSymbolMap() {
@@ -255,7 +258,7 @@ void GMainWindow::OnMenuLoadSymbolMap() {
255 258
256void GMainWindow::OnStartGame() 259void GMainWindow::OnStartGame()
257{ 260{
258 emu_thread->SetCpuRunning(true); 261 emu_thread->SetRunning(true);
259 262
260 ui.action_Start->setEnabled(false); 263 ui.action_Start->setEnabled(false);
261 ui.action_Pause->setEnabled(true); 264 ui.action_Pause->setEnabled(true);
@@ -264,7 +267,7 @@ void GMainWindow::OnStartGame()
264 267
265void GMainWindow::OnPauseGame() 268void GMainWindow::OnPauseGame()
266{ 269{
267 emu_thread->SetCpuRunning(false); 270 emu_thread->SetRunning(false);
268 271
269 ui.action_Start->setEnabled(true); 272 ui.action_Start->setEnabled(true);
270 ui.action_Pause->setEnabled(false); 273 ui.action_Pause->setEnabled(false);