mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40: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" | ||||
| 
 | ||||
| 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())); | ||||
| } | ||||
| 
 | ||||
|  | @ -42,20 +41,20 @@ void EmuThread::run() { | |||
|     // next execution step
 | ||||
|     bool was_active = false; | ||||
|     while (!stop_run) { | ||||
|         if (cpu_running) { | ||||
|         if (running) { | ||||
|             if (!was_active) | ||||
|                 emit DebugModeLeft(); | ||||
| 
 | ||||
|             Core::RunLoop(); | ||||
| 
 | ||||
|             was_active = cpu_running || exec_cpu_step; | ||||
|             was_active = running || exec_step; | ||||
|             if (!was_active) | ||||
|                 emit DebugModeEntered(); | ||||
|         } else if (exec_cpu_step) { | ||||
|         } else if (exec_step) { | ||||
|             if (!was_active) | ||||
|                 emit DebugModeLeft(); | ||||
| 
 | ||||
|             exec_cpu_step = false; | ||||
|             exec_step = false; | ||||
|             Core::SingleStep(); | ||||
|             emit DebugModeEntered(); | ||||
|             yieldCurrentThread(); | ||||
|  | @ -65,40 +64,8 @@ void EmuThread::run() { | |||
|     } | ||||
| 
 | ||||
|     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.
 | ||||
| // The corresponding functionality is handled in EmuThread instead
 | ||||
| class GGLWidgetInternal : public QGLWidget | ||||
|  |  | |||
|  | @ -25,66 +25,46 @@ public: | |||
| 
 | ||||
|     /**
 | ||||
|      * Start emulation (on new thread) | ||||
|      * | ||||
|      * @warning Only call when not running! | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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 | ||||
|      */ | ||||
|     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; }; | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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(); | ||||
|     void Shutdown() { stop_run = true; }; | ||||
| 
 | ||||
| private: | ||||
|     friend class GMainWindow; | ||||
| 
 | ||||
|     EmuThread(GRenderWindow* render_window); | ||||
| 
 | ||||
|     bool exec_cpu_step; | ||||
|     bool cpu_running; | ||||
|     bool exec_step; | ||||
|     bool running; | ||||
|     std::atomic<bool> stop_run; | ||||
| 
 | ||||
|     GRenderWindow* render_window; | ||||
| 
 | ||||
|     Common::Event shutdown_event; | ||||
| 
 | ||||
| signals: | ||||
|     /**
 | ||||
|      * Emitted when the CPU has halted execution | ||||
|  |  | |||
|  | @ -201,7 +201,7 @@ void DisassemblerWidget::Init() | |||
| 
 | ||||
| void DisassemblerWidget::OnContinue() | ||||
| { | ||||
|     main_window.GetEmuThread()->SetCpuRunning(true); | ||||
|     main_window.GetEmuThread()->SetRunning(true); | ||||
| } | ||||
| 
 | ||||
| void DisassemblerWidget::OnStep() | ||||
|  | @ -211,13 +211,13 @@ void DisassemblerWidget::OnStep() | |||
| 
 | ||||
| void DisassemblerWidget::OnStepInto() | ||||
| { | ||||
|     main_window.GetEmuThread()->SetCpuRunning(false); | ||||
|     main_window.GetEmuThread()->SetRunning(false); | ||||
|     main_window.GetEmuThread()->ExecStep(); | ||||
| } | ||||
| 
 | ||||
| void DisassemblerWidget::OnPause() | ||||
| { | ||||
|     main_window.GetEmuThread()->SetCpuRunning(false); | ||||
|     main_window.GetEmuThread()->SetRunning(false); | ||||
| 
 | ||||
|     // TODO: By now, the CPU might not have actually stopped...
 | ||||
|     if (Core::g_app_core) { | ||||
|  | @ -227,7 +227,7 @@ void DisassemblerWidget::OnPause() | |||
| 
 | ||||
| void DisassemblerWidget::OnToggleStartStop() | ||||
| { | ||||
|     main_window.GetEmuThread()->SetCpuRunning(!main_window.GetEmuThread()->IsCpuRunning()); | ||||
|     main_window.GetEmuThread()->SetRunning(!main_window.GetEmuThread()->IsRunning()); | ||||
| } | ||||
| 
 | ||||
| void DisassemblerWidget::OnDebugModeEntered() | ||||
|  | @ -235,7 +235,7 @@ void DisassemblerWidget::OnDebugModeEntered() | |||
|     ARMword next_instr = Core::g_app_core->GetPC(); | ||||
| 
 | ||||
|     if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) | ||||
|         main_window.GetEmuThread()->SetCpuRunning(false); | ||||
|         main_window.GetEmuThread()->SetRunning(false); | ||||
| 
 | ||||
|     model->SetNextInstruction(next_instr); | ||||
| 
 | ||||
|  |  | |||
|  | @ -199,10 +199,6 @@ void GMainWindow::OnDisplayTitleBars(bool show) | |||
| void GMainWindow::BootGame(std::string filename) { | ||||
|     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); | ||||
| 
 | ||||
|     // Load a game or die...
 | ||||
|  | @ -222,29 +218,36 @@ void GMainWindow::BootGame(std::string filename) { | |||
| } | ||||
| 
 | ||||
| void GMainWindow::ShutdownGame() { | ||||
|     emu_thread->SetCpuRunning(false); | ||||
| 
 | ||||
|     emu_thread->ShutdownCpu(); | ||||
|     emu_thread->WaitForCpuShutdown(); | ||||
|     emu_thread->Stop(); | ||||
| 
 | ||||
|     // Shutdown the emulation thread and wait for it to complete
 | ||||
|     emu_thread->SetRunning(false); | ||||
|     emu_thread->Shutdown(); | ||||
|     emu_thread->wait(); | ||||
|     delete emu_thread; | ||||
|     emu_thread = nullptr; | ||||
| 
 | ||||
|     // Release emu threads from any breakpoints
 | ||||
|     Pica::g_debug_context->ClearBreakpoints(); | ||||
| 
 | ||||
|     // Shutdown the core emulation
 | ||||
|     System::Shutdown(); | ||||
| 
 | ||||
|     // Update the GUI
 | ||||
|     ui.action_Start->setEnabled(true); | ||||
|     ui.action_Pause->setEnabled(false); | ||||
|     ui.action_Stop->setEnabled(false); | ||||
| 
 | ||||
|     render_window->hide(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnMenuLoadFile() | ||||
| { | ||||
|     QString filename = QFileDialog::getOpenFileName(this, tr("Load File"), QString(), tr("3DS executable (*.3ds *.3dsx *.elf *.axf *.bin *.cci *.cxi)")); | ||||
|     if (filename.size()) | ||||
|        BootGame(filename.toLatin1().data()); | ||||
|     if (filename.size()) { | ||||
|         // Shutdown previous session if the emu thread is still active...
 | ||||
|         if (emu_thread != nullptr) | ||||
|             ShutdownGame(); | ||||
| 
 | ||||
|         BootGame(filename.toLatin1().data()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnMenuLoadSymbolMap() { | ||||
|  | @ -255,7 +258,7 @@ void GMainWindow::OnMenuLoadSymbolMap() { | |||
| 
 | ||||
| void GMainWindow::OnStartGame() | ||||
| { | ||||
|     emu_thread->SetCpuRunning(true); | ||||
|     emu_thread->SetRunning(true); | ||||
| 
 | ||||
|     ui.action_Start->setEnabled(false); | ||||
|     ui.action_Pause->setEnabled(true); | ||||
|  | @ -264,7 +267,7 @@ void GMainWindow::OnStartGame() | |||
| 
 | ||||
| void GMainWindow::OnPauseGame() | ||||
| { | ||||
|     emu_thread->SetCpuRunning(false); | ||||
|     emu_thread->SetRunning(false); | ||||
| 
 | ||||
|     ui.action_Start->setEnabled(true); | ||||
|     ui.action_Pause->setEnabled(false); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue