mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Qt: Restructured to remove unnecessary shutdown event and various cleanups.
This commit is contained in:
		
							parent
							
								
									3dd2688785
								
							
						
					
					
						commit
						e4ea133717
					
				
					 4 changed files with 40 additions and 90 deletions
				
			
		|  | @ -28,9 +28,8 @@ | ||||||
| #define COPYRIGHT       "Copyright (C) 2013-2014 Citra Team" | #define COPYRIGHT       "Copyright (C) 2013-2014 Citra Team" | ||||||
| 
 | 
 | ||||||
| EmuThread::EmuThread(GRenderWindow* render_window) : | EmuThread::EmuThread(GRenderWindow* render_window) : | ||||||
|     exec_cpu_step(false), cpu_running(false), stop_run(false), render_window(render_window) { |     exec_step(false), running(false), stop_run(false), render_window(render_window) { | ||||||
| 
 | 
 | ||||||
|     shutdown_event.Reset(); |  | ||||||
|     connect(this, SIGNAL(started()), render_window, SLOT(moveContext())); |     connect(this, SIGNAL(started()), render_window, SLOT(moveContext())); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -42,20 +41,20 @@ void EmuThread::run() { | ||||||
|     // next execution step
 |     // next execution step
 | ||||||
|     bool was_active = false; |     bool was_active = false; | ||||||
|     while (!stop_run) { |     while (!stop_run) { | ||||||
|         if (cpu_running) { |         if (running) { | ||||||
|             if (!was_active) |             if (!was_active) | ||||||
|                 emit DebugModeLeft(); |                 emit DebugModeLeft(); | ||||||
| 
 | 
 | ||||||
|             Core::RunLoop(); |             Core::RunLoop(); | ||||||
| 
 | 
 | ||||||
|             was_active = cpu_running || exec_cpu_step; |             was_active = running || exec_step; | ||||||
|             if (!was_active) |             if (!was_active) | ||||||
|                 emit DebugModeEntered(); |                 emit DebugModeEntered(); | ||||||
|         } else if (exec_cpu_step) { |         } else if (exec_step) { | ||||||
|             if (!was_active) |             if (!was_active) | ||||||
|                 emit DebugModeLeft(); |                 emit DebugModeLeft(); | ||||||
| 
 | 
 | ||||||
|             exec_cpu_step = false; |             exec_step = false; | ||||||
|             Core::SingleStep(); |             Core::SingleStep(); | ||||||
|             emit DebugModeEntered(); |             emit DebugModeEntered(); | ||||||
|             yieldCurrentThread(); |             yieldCurrentThread(); | ||||||
|  | @ -65,40 +64,8 @@ void EmuThread::run() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     render_window->moveContext(); |     render_window->moveContext(); | ||||||
| 
 |  | ||||||
|     shutdown_event.Set(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EmuThread::Stop() { |  | ||||||
|     if (!isRunning()) { |  | ||||||
|         LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning..."); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     stop_run = true; |  | ||||||
| 
 |  | ||||||
|     // Release emu threads from any breakpoints, so that this doesn't hang forever.
 |  | ||||||
|     Pica::g_debug_context->ClearBreakpoints(); |  | ||||||
| 
 |  | ||||||
|     //core::g_state = core::SYS_DIE;
 |  | ||||||
| 
 |  | ||||||
|     // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
 |  | ||||||
|     wait(1000); |  | ||||||
|     if (isRunning()) { |  | ||||||
|         LOG_WARNING(Frontend, "EmuThread still running, terminating..."); |  | ||||||
|         quit(); |  | ||||||
| 
 |  | ||||||
|         // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
 |  | ||||||
|         // queued... This should be fixed.
 |  | ||||||
|         wait(50000); |  | ||||||
|         if (isRunning()) { |  | ||||||
|             LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here..."); |  | ||||||
|             terminate(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     LOG_INFO(Frontend, "EmuThread stopped"); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
 | // This class overrides paintEvent and resizeEvent to prevent the GUI thread from stealing GL context.
 | ||||||
| // The corresponding functionality is handled in EmuThread instead
 | // The corresponding functionality is handled in EmuThread instead
 | ||||||
| class GGLWidgetInternal : public QGLWidget | class GGLWidgetInternal : public QGLWidget | ||||||
|  |  | ||||||
|  | @ -25,66 +25,46 @@ public: | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Start emulation (on new thread) |      * Start emulation (on new thread) | ||||||
|      * |  | ||||||
|      * @warning Only call when not running! |      * @warning Only call when not running! | ||||||
|      */ |      */ | ||||||
|     void run() override; |     void run() override; | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Allow the CPU to process a single instruction (if cpu is not running) |      * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) | ||||||
|      * |  | ||||||
|      * @note This function is thread-safe |      * @note This function is thread-safe | ||||||
|      */ |      */ | ||||||
|     void ExecStep() { exec_cpu_step = true; } |     void ExecStep() { exec_step = true; } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Sets whether the CPU is running  |      * Sets whether the emulation thread is running or not | ||||||
|      * |      * @param running Boolean value, set the emulation thread to running if true | ||||||
|      * @note This function is thread-safe |      * @note This function is thread-safe | ||||||
|      */ |      */ | ||||||
|     void SetCpuRunning(bool running) { cpu_running = running; } |     void SetRunning(bool running) { this->running = running; } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Allow the CPU to continue processing instructions without interruption |      * Check if the emulation thread is running or not | ||||||
|      * |      * @return True if the emulation thread is running, otherwise false | ||||||
|      * @note This function is thread-safe |      * @note This function is thread-safe | ||||||
|      */ |      */ | ||||||
|     bool IsCpuRunning() { return cpu_running; } |     bool IsRunning() { return running; } | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Shutdown (permantently stops) the CPU |      * Shutdown (permanently stops) the emulation thread | ||||||
|      */ |      */ | ||||||
|     void ShutdownCpu() { stop_run = true; }; |     void Shutdown() { stop_run = true; }; | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * Waits for the CPU shutdown to complete |  | ||||||
|      */ |  | ||||||
|     void WaitForCpuShutdown() { shutdown_event.Wait(); } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| public slots: |  | ||||||
|     /**
 |  | ||||||
|      * Stop emulation and wait for the thread to finish. |  | ||||||
|      * |  | ||||||
|      * @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. |  | ||||||
|      * @note: This function is thread-safe. |  | ||||||
|      */ |  | ||||||
|     void Stop(); |  | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     friend class GMainWindow; |     friend class GMainWindow; | ||||||
| 
 | 
 | ||||||
|     EmuThread(GRenderWindow* render_window); |     EmuThread(GRenderWindow* render_window); | ||||||
| 
 | 
 | ||||||
|     bool exec_cpu_step; |     bool exec_step; | ||||||
|     bool cpu_running; |     bool running; | ||||||
|     std::atomic<bool> stop_run; |     std::atomic<bool> stop_run; | ||||||
| 
 | 
 | ||||||
|     GRenderWindow* render_window; |     GRenderWindow* render_window; | ||||||
| 
 | 
 | ||||||
|     Common::Event shutdown_event; |  | ||||||
| 
 |  | ||||||
| signals: | signals: | ||||||
|     /**
 |     /**
 | ||||||
|      * Emitted when the CPU has halted execution |      * Emitted when the CPU has halted execution | ||||||
|  |  | ||||||
|  | @ -201,7 +201,7 @@ void DisassemblerWidget::Init() | ||||||
| 
 | 
 | ||||||
| void DisassemblerWidget::OnContinue() | void DisassemblerWidget::OnContinue() | ||||||
| { | { | ||||||
|     main_window.GetEmuThread()->SetCpuRunning(true); |     main_window.GetEmuThread()->SetRunning(true); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DisassemblerWidget::OnStep() | void DisassemblerWidget::OnStep() | ||||||
|  | @ -211,13 +211,13 @@ void DisassemblerWidget::OnStep() | ||||||
| 
 | 
 | ||||||
| void DisassemblerWidget::OnStepInto() | void DisassemblerWidget::OnStepInto() | ||||||
| { | { | ||||||
|     main_window.GetEmuThread()->SetCpuRunning(false); |     main_window.GetEmuThread()->SetRunning(false); | ||||||
|     main_window.GetEmuThread()->ExecStep(); |     main_window.GetEmuThread()->ExecStep(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DisassemblerWidget::OnPause() | void DisassemblerWidget::OnPause() | ||||||
| { | { | ||||||
|     main_window.GetEmuThread()->SetCpuRunning(false); |     main_window.GetEmuThread()->SetRunning(false); | ||||||
| 
 | 
 | ||||||
|     // TODO: By now, the CPU might not have actually stopped...
 |     // TODO: By now, the CPU might not have actually stopped...
 | ||||||
|     if (Core::g_app_core) { |     if (Core::g_app_core) { | ||||||
|  | @ -227,7 +227,7 @@ void DisassemblerWidget::OnPause() | ||||||
| 
 | 
 | ||||||
| void DisassemblerWidget::OnToggleStartStop() | void DisassemblerWidget::OnToggleStartStop() | ||||||
| { | { | ||||||
|     main_window.GetEmuThread()->SetCpuRunning(!main_window.GetEmuThread()->IsCpuRunning()); |     main_window.GetEmuThread()->SetRunning(!main_window.GetEmuThread()->IsRunning()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DisassemblerWidget::OnDebugModeEntered() | void DisassemblerWidget::OnDebugModeEntered() | ||||||
|  | @ -235,7 +235,7 @@ void DisassemblerWidget::OnDebugModeEntered() | ||||||
|     ARMword next_instr = Core::g_app_core->GetPC(); |     ARMword next_instr = Core::g_app_core->GetPC(); | ||||||
| 
 | 
 | ||||||
|     if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) |     if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) | ||||||
|         main_window.GetEmuThread()->SetCpuRunning(false); |         main_window.GetEmuThread()->SetRunning(false); | ||||||
| 
 | 
 | ||||||
|     model->SetNextInstruction(next_instr); |     model->SetNextInstruction(next_instr); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -199,10 +199,6 @@ void GMainWindow::OnDisplayTitleBars(bool show) | ||||||
| void GMainWindow::BootGame(std::string filename) { | void GMainWindow::BootGame(std::string filename) { | ||||||
|     LOG_INFO(Frontend, "Citra starting...\n"); |     LOG_INFO(Frontend, "Citra starting...\n"); | ||||||
| 
 | 
 | ||||||
|     // Shutdown previous session if the emu thread is still active...
 |  | ||||||
|     if (emu_thread != nullptr) |  | ||||||
|         ShutdownGame(); |  | ||||||
| 
 |  | ||||||
|     System::Init(render_window); |     System::Init(render_window); | ||||||
| 
 | 
 | ||||||
|     // Load a game or die...
 |     // Load a game or die...
 | ||||||
|  | @ -222,29 +218,36 @@ void GMainWindow::BootGame(std::string filename) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::ShutdownGame() { | void GMainWindow::ShutdownGame() { | ||||||
|     emu_thread->SetCpuRunning(false); |     // Shutdown the emulation thread and wait for it to complete
 | ||||||
| 
 |     emu_thread->SetRunning(false); | ||||||
|     emu_thread->ShutdownCpu(); |     emu_thread->Shutdown(); | ||||||
|     emu_thread->WaitForCpuShutdown(); |     emu_thread->wait(); | ||||||
|     emu_thread->Stop(); |  | ||||||
| 
 |  | ||||||
|     delete emu_thread; |     delete emu_thread; | ||||||
|     emu_thread = nullptr; |     emu_thread = nullptr; | ||||||
| 
 | 
 | ||||||
|  |     // Release emu threads from any breakpoints
 | ||||||
|  |     Pica::g_debug_context->ClearBreakpoints(); | ||||||
|  | 
 | ||||||
|  |     // Shutdown the core emulation
 | ||||||
|     System::Shutdown(); |     System::Shutdown(); | ||||||
| 
 | 
 | ||||||
|  |     // Update the GUI
 | ||||||
|     ui.action_Start->setEnabled(true); |     ui.action_Start->setEnabled(true); | ||||||
|     ui.action_Pause->setEnabled(false); |     ui.action_Pause->setEnabled(false); | ||||||
|     ui.action_Stop->setEnabled(false); |     ui.action_Stop->setEnabled(false); | ||||||
| 
 |  | ||||||
|     render_window->hide(); |     render_window->hide(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnMenuLoadFile() | void GMainWindow::OnMenuLoadFile() | ||||||
| { | { | ||||||
|     QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)")); |     QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)")); | ||||||
|     if (filename.size()) |     if (filename.size()) { | ||||||
|        BootGame(filename.toLatin1().data()); |         // Shutdown previous session if the emu thread is still active...
 | ||||||
|  |         if (emu_thread != nullptr) | ||||||
|  |             ShutdownGame(); | ||||||
|  | 
 | ||||||
|  |         BootGame(filename.toLatin1().data()); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnMenuLoadSymbolMap() { | void GMainWindow::OnMenuLoadSymbolMap() { | ||||||
|  | @ -255,7 +258,7 @@ void GMainWindow::OnMenuLoadSymbolMap() { | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnStartGame() | void GMainWindow::OnStartGame() | ||||||
| { | { | ||||||
|     emu_thread->SetCpuRunning(true); |     emu_thread->SetRunning(true); | ||||||
| 
 | 
 | ||||||
|     ui.action_Start->setEnabled(false); |     ui.action_Start->setEnabled(false); | ||||||
|     ui.action_Pause->setEnabled(true); |     ui.action_Pause->setEnabled(true); | ||||||
|  | @ -264,7 +267,7 @@ void GMainWindow::OnStartGame() | ||||||
| 
 | 
 | ||||||
| void GMainWindow::OnPauseGame() | void GMainWindow::OnPauseGame() | ||||||
| { | { | ||||||
|     emu_thread->SetCpuRunning(false); |     emu_thread->SetRunning(false); | ||||||
| 
 | 
 | ||||||
|     ui.action_Start->setEnabled(true); |     ui.action_Start->setEnabled(true); | ||||||
|     ui.action_Pause->setEnabled(false); |     ui.action_Pause->setEnabled(false); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue