forked from eden-emu/eden
		
	Merge pull request #9463 from liamwhite/manager-events
EmuThread: refactor
This commit is contained in:
		
						commit
						1b11e0f0d3
					
				
					 6 changed files with 65 additions and 173 deletions
				
			
		|  | @ -183,26 +183,20 @@ struct System::Impl { | |||
|         Initialize(system); | ||||
|     } | ||||
| 
 | ||||
|     SystemResultStatus Run() { | ||||
|     void Run() { | ||||
|         std::unique_lock<std::mutex> lk(suspend_guard); | ||||
|         status = SystemResultStatus::Success; | ||||
| 
 | ||||
|         kernel.Suspend(false); | ||||
|         core_timing.SyncPause(false); | ||||
|         is_paused.store(false, std::memory_order_relaxed); | ||||
| 
 | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
|     SystemResultStatus Pause() { | ||||
|     void Pause() { | ||||
|         std::unique_lock<std::mutex> lk(suspend_guard); | ||||
|         status = SystemResultStatus::Success; | ||||
| 
 | ||||
|         core_timing.SyncPause(true); | ||||
|         kernel.Suspend(true); | ||||
|         is_paused.store(true, std::memory_order_relaxed); | ||||
| 
 | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
|     bool IsPaused() const { | ||||
|  | @ -553,12 +547,12 @@ void System::Initialize() { | |||
|     impl->Initialize(*this); | ||||
| } | ||||
| 
 | ||||
| SystemResultStatus System::Run() { | ||||
|     return impl->Run(); | ||||
| void System::Run() { | ||||
|     impl->Run(); | ||||
| } | ||||
| 
 | ||||
| SystemResultStatus System::Pause() { | ||||
|     return impl->Pause(); | ||||
| void System::Pause() { | ||||
|     impl->Pause(); | ||||
| } | ||||
| 
 | ||||
| bool System::IsPaused() const { | ||||
|  |  | |||
|  | @ -152,13 +152,13 @@ public: | |||
|      * Run the OS and Application | ||||
|      * This function will start emulation and run the relevant devices | ||||
|      */ | ||||
|     [[nodiscard]] SystemResultStatus Run(); | ||||
|     void Run(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Pause the OS and Application | ||||
|      * This function will pause emulation and stop the relevant devices | ||||
|      */ | ||||
|     [[nodiscard]] SystemResultStatus Pause(); | ||||
|     void Pause(); | ||||
| 
 | ||||
|     /// Check if the core is currently paused.
 | ||||
|     [[nodiscard]] bool IsPaused() const; | ||||
|  |  | |||
|  | @ -46,30 +46,28 @@ | |||
| 
 | ||||
| static Core::Frontend::WindowSystemType GetWindowSystemType(); | ||||
| 
 | ||||
| EmuThread::EmuThread(Core::System& system_) : system{system_} {} | ||||
| EmuThread::EmuThread(Core::System& system) : m_system{system} {} | ||||
| 
 | ||||
| EmuThread::~EmuThread() = default; | ||||
| 
 | ||||
| void EmuThread::run() { | ||||
|     std::string name = "EmuControlThread"; | ||||
|     MicroProfileOnThreadCreate(name.c_str()); | ||||
|     Common::SetCurrentThreadName(name.c_str()); | ||||
|     const char* name = "EmuControlThread"; | ||||
|     MicroProfileOnThreadCreate(name); | ||||
|     Common::SetCurrentThreadName(name); | ||||
| 
 | ||||
|     auto& gpu = system.GPU(); | ||||
|     auto stop_token = stop_source.get_token(); | ||||
|     bool debugger_should_start = system.DebuggerEnabled(); | ||||
|     auto& gpu = m_system.GPU(); | ||||
|     auto stop_token = m_stop_source.get_token(); | ||||
| 
 | ||||
|     system.RegisterHostThread(); | ||||
|     m_system.RegisterHostThread(); | ||||
| 
 | ||||
|     // Main process has been loaded. Make the context current to this thread and begin GPU and CPU
 | ||||
|     // execution.
 | ||||
|     gpu.ObtainContext(); | ||||
| 
 | ||||
|     emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | ||||
| 
 | ||||
|     if (Settings::values.use_disk_shader_cache.GetValue()) { | ||||
|         system.Renderer().ReadRasterizer()->LoadDiskResources( | ||||
|             system.GetCurrentProcessProgramID(), stop_token, | ||||
|         m_system.Renderer().ReadRasterizer()->LoadDiskResources( | ||||
|             m_system.GetCurrentProcessProgramID(), stop_token, | ||||
|             [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { | ||||
|                 emit LoadProgress(stage, value, total); | ||||
|             }); | ||||
|  | @ -79,57 +77,35 @@ void EmuThread::run() { | |||
|     gpu.ReleaseContext(); | ||||
|     gpu.Start(); | ||||
| 
 | ||||
|     system.GetCpuManager().OnGpuReady(); | ||||
|     m_system.GetCpuManager().OnGpuReady(); | ||||
|     m_system.RegisterExitCallback([this] { m_stop_source.request_stop(); }); | ||||
| 
 | ||||
|     system.RegisterExitCallback([this]() { | ||||
|         stop_source.request_stop(); | ||||
|         SetRunning(false); | ||||
|     }); | ||||
|     if (m_system.DebuggerEnabled()) { | ||||
|         m_system.InitializeDebugger(); | ||||
|     } | ||||
| 
 | ||||
|     // Holds whether the cpu was running during the last iteration,
 | ||||
|     // so that the DebugModeLeft signal can be emitted before the
 | ||||
|     // next execution step
 | ||||
|     bool was_active = false; | ||||
|     while (!stop_token.stop_requested()) { | ||||
|         if (running) { | ||||
|             if (was_active) { | ||||
|                 emit DebugModeLeft(); | ||||
|             } | ||||
|         std::unique_lock lk{m_should_run_mutex}; | ||||
|         if (m_should_run) { | ||||
|             m_system.Run(); | ||||
|             m_is_running.store(true); | ||||
|             m_is_running.notify_all(); | ||||
| 
 | ||||
|             running_guard = true; | ||||
|             Core::SystemResultStatus result = system.Run(); | ||||
|             if (result != Core::SystemResultStatus::Success) { | ||||
|                 running_guard = false; | ||||
|                 this->SetRunning(false); | ||||
|                 emit ErrorThrown(result, system.GetStatusDetails()); | ||||
|             } | ||||
| 
 | ||||
|             if (debugger_should_start) { | ||||
|                 system.InitializeDebugger(); | ||||
|                 debugger_should_start = false; | ||||
|             } | ||||
| 
 | ||||
|             running_wait.Wait(); | ||||
|             result = system.Pause(); | ||||
|             if (result != Core::SystemResultStatus::Success) { | ||||
|                 running_guard = false; | ||||
|                 this->SetRunning(false); | ||||
|                 emit ErrorThrown(result, system.GetStatusDetails()); | ||||
|             } | ||||
|             running_guard = false; | ||||
| 
 | ||||
|             if (!stop_token.stop_requested()) { | ||||
|                 was_active = true; | ||||
|                 emit DebugModeEntered(); | ||||
|             } | ||||
|             Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); | ||||
|         } else { | ||||
|             std::unique_lock lock{running_mutex}; | ||||
|             Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); }); | ||||
|             m_system.Pause(); | ||||
|             m_is_running.store(false); | ||||
|             m_is_running.notify_all(); | ||||
| 
 | ||||
|             emit DebugModeEntered(); | ||||
|             Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); | ||||
|             emit DebugModeLeft(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Shutdown the main emulated process
 | ||||
|     system.ShutdownMainProcess(); | ||||
|     m_system.DetachDebugger(); | ||||
|     m_system.ShutdownMainProcess(); | ||||
| 
 | ||||
| #if MICROPROFILE_ENABLED | ||||
|     MicroProfileOnThreadExit(); | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ class EmuThread final : public QThread { | |||
|     Q_OBJECT | ||||
| 
 | ||||
| public: | ||||
|     explicit EmuThread(Core::System& system_); | ||||
|     explicit EmuThread(Core::System& system); | ||||
|     ~EmuThread() override; | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -57,30 +57,30 @@ public: | |||
|     void run() override; | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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 | ||||
|      * Sets whether the emulation thread should run or not | ||||
|      * @param should_run Boolean value, set the emulation thread to running if true | ||||
|      */ | ||||
|     void SetRunning(bool running_) { | ||||
|         std::unique_lock lock{running_mutex}; | ||||
|         running = running_; | ||||
|         lock.unlock(); | ||||
|         running_cv.notify_all(); | ||||
|         if (!running) { | ||||
|             running_wait.Set(); | ||||
|             /// Wait until effectively paused
 | ||||
|             while (running_guard) | ||||
|                 ; | ||||
|     void SetRunning(bool should_run) { | ||||
|         // TODO: Prevent other threads from modifying the state until we finish.
 | ||||
|         { | ||||
|             // Notify the running thread to change state.
 | ||||
|             std::unique_lock run_lk{m_should_run_mutex}; | ||||
|             m_should_run = should_run; | ||||
|             m_should_run_cv.notify_one(); | ||||
|         } | ||||
| 
 | ||||
|         // Wait until paused, if pausing.
 | ||||
|         if (!should_run) { | ||||
|             m_is_running.wait(true); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * 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 IsRunning() const { | ||||
|         return running; | ||||
|         return m_is_running.load(); | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -88,18 +88,17 @@ public: | |||
|      */ | ||||
|     void ForceStop() { | ||||
|         LOG_WARNING(Frontend, "Force stopping EmuThread"); | ||||
|         stop_source.request_stop(); | ||||
|         SetRunning(false); | ||||
|         m_stop_source.request_stop(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     bool running = false; | ||||
|     std::stop_source stop_source; | ||||
|     std::mutex running_mutex; | ||||
|     std::condition_variable_any running_cv; | ||||
|     Common::Event running_wait{}; | ||||
|     std::atomic_bool running_guard{false}; | ||||
|     Core::System& system; | ||||
|     Core::System& m_system; | ||||
| 
 | ||||
|     std::stop_source m_stop_source; | ||||
|     std::mutex m_should_run_mutex; | ||||
|     std::condition_variable_any m_should_run_cv; | ||||
|     std::atomic<bool> m_is_running{false}; | ||||
|     bool m_should_run{true}; | ||||
| 
 | ||||
| signals: | ||||
|     /**
 | ||||
|  | @ -120,8 +119,6 @@ signals: | |||
|      */ | ||||
|     void DebugModeLeft(); | ||||
| 
 | ||||
|     void ErrorThrown(Core::SystemResultStatus, std::string); | ||||
| 
 | ||||
|     void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1498,7 +1498,7 @@ void GMainWindow::SetupSigInterrupts() { | |||
| 
 | ||||
| void GMainWindow::HandleSigInterrupt(int sig) { | ||||
|     if (sig == SIGINT) { | ||||
|         exit(1); | ||||
|         _exit(1); | ||||
|     } | ||||
| 
 | ||||
|     // Calling into Qt directly from a signal handler is not safe,
 | ||||
|  | @ -1794,15 +1794,16 @@ void GMainWindow::ShutdownGame() { | |||
|     Settings::values.use_speed_limit.SetValue(true); | ||||
| 
 | ||||
|     system->SetShuttingDown(true); | ||||
|     system->DetachDebugger(); | ||||
|     discord_rpc->Pause(); | ||||
| 
 | ||||
|     RequestGameExit(); | ||||
|     emu_thread->disconnect(); | ||||
|     emu_thread->SetRunning(true); | ||||
| 
 | ||||
|     emit EmulationStopping(); | ||||
| 
 | ||||
|     // Wait for emulation thread to complete and delete it
 | ||||
|     if (!emu_thread->wait(5000)) { | ||||
|     if (system->DebuggerEnabled() || !emu_thread->wait(5000)) { | ||||
|         emu_thread->ForceStop(); | ||||
|         emu_thread->wait(); | ||||
|     } | ||||
|  | @ -2919,8 +2920,6 @@ void GMainWindow::OnStartGame() { | |||
| 
 | ||||
|     emu_thread->SetRunning(true); | ||||
| 
 | ||||
|     connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); | ||||
| 
 | ||||
|     UpdateMenuState(); | ||||
|     OnTasStateChanged(); | ||||
| 
 | ||||
|  | @ -3904,79 +3903,6 @@ void GMainWindow::OnMouseActivity() { | |||
|     mouse_center_timer.stop(); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) { | ||||
|     QMessageBox::StandardButton answer; | ||||
|     QString status_message; | ||||
|     const QString common_message = | ||||
|         tr("The game you are trying to load requires additional files from your Switch to be " | ||||
|            "dumped " | ||||
|            "before playing.<br/><br/>For more information on dumping these files, please see the " | ||||
|            "following wiki page: <a " | ||||
|            "href='https://yuzu-emu.org/wiki/" | ||||
|            "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System " | ||||
|            "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to " | ||||
|            "quit " | ||||
|            "back to the game list? Continuing emulation may result in crashes, corrupted save " | ||||
|            "data, or other bugs."); | ||||
|     switch (result) { | ||||
|     case Core::SystemResultStatus::ErrorSystemFiles: { | ||||
|         QString message; | ||||
|         if (details.empty()) { | ||||
|             message = | ||||
|                 tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message); | ||||
|         } else { | ||||
|             message = tr("yuzu was unable to locate a Switch system archive: %1. %2") | ||||
|                           .arg(QString::fromStdString(details), common_message); | ||||
|         } | ||||
| 
 | ||||
|         answer = QMessageBox::question(this, tr("System Archive Not Found"), message, | ||||
|                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||||
|         status_message = tr("System Archive Missing"); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     case Core::SystemResultStatus::ErrorSharedFont: { | ||||
|         const QString message = | ||||
|             tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message); | ||||
|         answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message, | ||||
|                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||||
|         status_message = tr("Shared Font Missing"); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     default: | ||||
|         answer = QMessageBox::question( | ||||
|             this, tr("Fatal Error"), | ||||
|             tr("yuzu has encountered a fatal error, please see the log for more details. " | ||||
|                "For more information on accessing the log, please see the following page: " | ||||
|                "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How " | ||||
|                "to " | ||||
|                "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game " | ||||
|                "list? " | ||||
|                "Continuing emulation may result in crashes, corrupted save data, or other " | ||||
|                "bugs."), | ||||
|             QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||||
|         status_message = tr("Fatal Error encountered"); | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     if (answer == QMessageBox::Yes) { | ||||
|         if (emu_thread) { | ||||
|             ShutdownGame(); | ||||
| 
 | ||||
|             Settings::RestoreGlobalState(system->IsPoweredOn()); | ||||
|             system->HIDCore().ReloadInputDevices(); | ||||
|             UpdateStatusButtons(); | ||||
|         } | ||||
|     } else { | ||||
|         // Only show the message if the game is still running.
 | ||||
|         if (emu_thread) { | ||||
|             emu_thread->SetRunning(true); | ||||
|             message_label->setText(status_message); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | ||||
|     if (behavior == ReinitializeKeyBehavior::Warning) { | ||||
|         const auto res = QMessageBox::information( | ||||
|  |  | |||
|  | @ -332,7 +332,6 @@ private slots: | |||
|     void ResetWindowSize900(); | ||||
|     void ResetWindowSize1080(); | ||||
|     void OnCaptureScreenshot(); | ||||
|     void OnCoreError(Core::SystemResultStatus, std::string); | ||||
|     void OnReinitializeKeys(ReinitializeKeyBehavior behavior); | ||||
|     void OnLanguageChanged(const QString& locale); | ||||
|     void OnMouseActivity(); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 liamwhite
						liamwhite