From 251dc590ddb943646921513c256bd327e6804306 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 21 Sep 2026 00:39:13 +0000 Subject: [PATCH] 2026-09-21 00:39:13 Signed-off-by: lizzie --- src/audio_core/adsp/adsp.cpp | 4 ++ src/audio_core/adsp/adsp.h | 1 + .../adsp/apps/opus/opus_decoder.cpp | 8 +++ src/audio_core/adsp/apps/opus/opus_decoder.h | 2 + src/audio_core/audio_core.cpp | 5 ++ src/audio_core/audio_core.h | 2 + src/audio_core/audio_manager.cpp | 7 +- src/audio_core/audio_manager.h | 7 +- src/core/core.cpp | 64 +++++++++++++------ src/core/hle/kernel/k_process.cpp | 1 - src/core/hle/kernel/kernel.cpp | 5 ++ src/core/hle/service/server_manager.cpp | 10 ++- src/core/hle/service/server_manager.h | 1 + 13 files changed, 90 insertions(+), 27 deletions(-) diff --git a/src/audio_core/adsp/adsp.cpp b/src/audio_core/adsp/adsp.cpp index a578461f7c..0bfc479f10 100644 --- a/src/audio_core/adsp/adsp.cpp +++ b/src/audio_core/adsp/adsp.cpp @@ -19,6 +19,10 @@ ADSP::ADSP(Core::System& system, Sink::Sink& sink) { } } +void ADSP::NotifyShutdown() { + opus_decoder->NotifyShutdown(); +} + AudioRenderer::AudioRenderer& ADSP::AudioRenderer() { return *audio_renderer; } diff --git a/src/audio_core/adsp/adsp.h b/src/audio_core/adsp/adsp.h index 028d87939d..6629234257 100644 --- a/src/audio_core/adsp/adsp.h +++ b/src/audio_core/adsp/adsp.h @@ -45,6 +45,7 @@ public: explicit ADSP(Core::System& system, Sink::Sink& sink); ~ADSP() = default; + void NotifyShutdown(); AudioRenderer::AudioRenderer& AudioRenderer(); OpusDecoder::OpusDecoder& OpusDecoder(); diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.cpp b/src/audio_core/adsp/apps/opus/opus_decoder.cpp index 8a009c04c7..c1724496db 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.cpp +++ b/src/audio_core/adsp/apps/opus/opus_decoder.cpp @@ -82,6 +82,9 @@ void OpusDecoder::Main(std::stop_token stop_token) { while (!stop_token.stop_requested()) { auto msg = Receive(Direction::DSP, stop_token); + if (stop_token.stop_requested()) + break; + switch (msg) { case Shutdown: Send(Direction::Host, Message::ShutdownOK); @@ -266,4 +269,9 @@ void OpusDecoder::Main(std::stop_token stop_token) { } } +void OpusDecoder::NotifyShutdown() { + init_thread.request_stop(); + main_thread.request_stop(); +} + } // namespace AudioCore::ADSP::OpusDecoder diff --git a/src/audio_core/adsp/apps/opus/opus_decoder.h b/src/audio_core/adsp/apps/opus/opus_decoder.h index 5b3f22bf4c..1cae3b455a 100644 --- a/src/audio_core/adsp/apps/opus/opus_decoder.h +++ b/src/audio_core/adsp/apps/opus/opus_decoder.h @@ -67,6 +67,8 @@ public: shared_memory = &shared_memory_; } + void NotifyShutdown(); + private: /** * Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread. diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp index 234c831ac0..a12fa2d308 100644 --- a/src/audio_core/audio_core.cpp +++ b/src/audio_core/audio_core.cpp @@ -31,6 +31,11 @@ void AudioCore::CreateSinks() { input_sink = Sink::CreateSinkFromID(sink_id.GetValue(), audio_input_device_id.GetValue()); } +void AudioCore::NotifyShutdown() { + audio_manager->NotifyShutdown(); + adsp->NotifyShutdown(); +} + void AudioCore::Shutdown() { audio_manager->Shutdown(); } diff --git a/src/audio_core/audio_core.h b/src/audio_core/audio_core.h index ababd780b1..6972e0dc89 100644 --- a/src/audio_core/audio_core.h +++ b/src/audio_core/audio_core.h @@ -24,6 +24,8 @@ public: explicit AudioCore(Core::System& system); ~AudioCore(); + void NotifyShutdown(); + /** * Shutdown the audio core. */ diff --git a/src/audio_core/audio_manager.cpp b/src/audio_core/audio_manager.cpp index 93142a53fb..783a1267ca 100644 --- a/src/audio_core/audio_manager.cpp +++ b/src/audio_core/audio_manager.cpp @@ -17,7 +17,7 @@ AudioManager::AudioManager() { std::unique_lock l{events.GetAudioEventLock()}; events.ClearEvents(); while (!stop_token.stop_requested()) { - const auto timed_out{events.Wait(l, std::chrono::seconds(2))}; + const auto timed_out = events.Wait(l, std::chrono::seconds{2}); if (events.CheckAudioEventSet(Event::Type::Max)) { break; } @@ -34,6 +34,11 @@ AudioManager::AudioManager() { }); } +void AudioManager::NotifyShutdown() { + events.SetAudioEvent(Event::Type::Max, true); + thread.request_stop(); +} + void AudioManager::Shutdown() { events.SetAudioEvent(Event::Type::Max, true); if (thread.joinable()) { diff --git a/src/audio_core/audio_manager.h b/src/audio_core/audio_manager.h index 0194aa16db..e40370bbad 100644 --- a/src/audio_core/audio_manager.h +++ b/src/audio_core/audio_manager.h @@ -39,9 +39,10 @@ class AudioManager { public: explicit AudioManager(); - /** - * Shutdown the audio manager. - */ + /// @brief Notify of impending shutdown + void NotifyShutdown(); + + /// @brief Shutdown the audio manager. void Shutdown(); /** diff --git a/src/core/core.cpp b/src/core/core.cpp index 4038b04bca..5b6b5e75b3 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -110,8 +110,13 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) - : kernel{system}, fs_controller{system}, hid_core{kernel}, cpu_manager{system}, - reporter{system}, applet_manager{system}, frontend_applets{system}, profile_manager{} {} + : kernel{system} + , fs_controller{system} + , hid_core{kernel} + , cpu_manager{system} + , reporter{system} + , profile_manager{} + {} u64 program_id; @@ -124,6 +129,12 @@ struct System::Impl { core_timing.SetMulticore(is_multicore); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); + applet_manager.emplace(system); + frontend_applets.emplace(system); + apm_controller.emplace(core_timing); + arp_manager.emplace(); + profile_manager.emplace(); + // Create a default fs if one doesn't already exist. if (virtual_filesystem == nullptr) { virtual_filesystem = std::make_shared(); @@ -133,7 +144,7 @@ struct System::Impl { } // Create default implementations of applets if one is not provided. - frontend_applets.SetDefaultAppletsIfMissing(); + frontend_applets->SetDefaultAppletsIfMissing(); auto const is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); @@ -376,7 +387,7 @@ struct System::Impl { // Register with applet manager // All threads are started, begin main process execution, now that we're in the clear - applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params); + applet_manager->CreateAndInsertByFrontendAppletParameters(std::move(process), params); if (Settings::values.gamecard_inserted) { if (Settings::values.gamecard_current_game) { @@ -429,9 +440,22 @@ struct System::Impl { Network::CancelPendingSocketOperations(); kernel.SuspendEmulation(true); kernel.ShutdownCores(); + + // Notify services helpers of shutdown + audio_core->NotifyShutdown(); + + // Wait for threads/services to join kernel.CloseServices(); + + // service shutdown services.reset(); service_manager.reset(); + frontend_applets.reset(); + applet_manager.reset(); + apm_controller.reset(); + arp_manager.reset(); + profile_manager.reset(); + fs_controller.Reset(); cheat_engine.reset(); core_timing.ClearPendingEvents(); @@ -452,7 +476,7 @@ struct System::Impl { } // Reset all glue registrations - arp_manager.ResetAll(); + arp_manager->ResetAll(); LOG_DEBUG(Core, "Shutdown OK"); } @@ -482,13 +506,13 @@ struct System::Impl { CpuManager cpu_manager; Reporter reporter; /// Applets - Service::AM::AppletManager applet_manager; - Service::AM::Frontend::FrontendAppletHolder frontend_applets; + std::optional applet_manager; + std::optional frontend_applets; /// APM (Performance) services - Service::APM::Controller apm_controller{core_timing}; + std::optional apm_controller; /// Service State - Service::Glue::ARPManager arp_manager; - Service::Account::ProfileManager profile_manager; + std::optional arp_manager; + std::optional profile_manager; /// Network instance Network::NetworkInstance network_instance; Core::SpeedLimiter speed_limiter; @@ -815,19 +839,19 @@ void System::RegisterCheatList(const std::vector& list, } void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) { - impl->frontend_applets.SetFrontendAppletSet(std::move(set)); + impl->frontend_applets->SetFrontendAppletSet(std::move(set)); } Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() { - return impl->frontend_applets; + return *impl->frontend_applets; } const Service::AM::Frontend::FrontendAppletHolder& System::GetFrontendAppletHolder() const { - return impl->frontend_applets; + return *impl->frontend_applets; } Service::AM::AppletManager& System::GetAppletManager() { - return impl->applet_manager; + return *impl->applet_manager; } void System::SetContentProvider(std::unique_ptr provider) { @@ -868,27 +892,27 @@ const Reporter& System::GetReporter() const { } Service::Glue::ARPManager& System::GetARPManager() { - return impl->arp_manager; + return *impl->arp_manager; } const Service::Glue::ARPManager& System::GetARPManager() const { - return impl->arp_manager; + return *impl->arp_manager; } Service::APM::Controller& System::GetAPMController() { - return impl->apm_controller; + return *impl->apm_controller; } const Service::APM::Controller& System::GetAPMController() const { - return impl->apm_controller; + return *impl->apm_controller; } Service::Account::ProfileManager& System::GetProfileManager() { - return impl->profile_manager; + return *impl->profile_manager; } const Service::Account::ProfileManager& System::GetProfileManager() const { - return impl->profile_manager; + return *impl->profile_manager; } void System::SetExitLocked(bool locked) { diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 27d1b1bfc4..6917e19130 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -59,7 +59,6 @@ Result TerminateChildren(KernelCore& kernel, KProcess* process, const KThread* t KThread* cur_child = nullptr; { KScopedLightLock proc_lk(process->GetListLock()); - auto& thread_list = process->GetThreadList(); for (auto it = thread_list.begin(); it != thread_list.end(); ++it) { if (KThread* thread = std::addressof(*it); thread != thread_to_not_terminate) { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 39bb57826e..57668ad02d 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -1253,6 +1253,11 @@ void KernelCore::SuspendEmulation(bool suspended) { } void KernelCore::ShutdownCores() { + // Notify shutdown (pre-emptively) + for (auto& sm : impl->server_managers) { + sm->NotifyShutdown(); + } + impl->TerminateAllProcesses(); KScopedSchedulerLock lk{*this}; for (auto* thread : impl->shutdown_threads) diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp index 4b3db04c76..6b5b570671 100644 --- a/src/core/hle/service/server_manager.cpp +++ b/src/core/hle/service/server_manager.cpp @@ -253,6 +253,13 @@ void ServerManager::StartAdditionalHostThreads(const char* name, size_t num_thre } } +/// @brief Notifies that the system is shutting down (pre-emptively terminate threads) +void ServerManager::NotifyShutdown() { + m_stop_source.request_stop(); + // Wake them up regardless + m_wakeup_event->Signal(m_system.Kernel()); +} + Result ServerManager::LoopProcess() { SCOPE_EXIT { m_stopped.Set(); @@ -285,9 +292,8 @@ MultiWaitHolder* ServerManager::WaitSignaled() { this->LinkDeferred(); // If we're done, return before we start waiting. - if (m_stop_source.stop_requested()) { + if (m_stop_source.stop_requested()) return nullptr; - } auto* selected = m_multi_wait.WaitAny(m_system.Kernel()); if (selected == std::addressof(*m_wakeup_holder)) { diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h index 5173ce46e1..1eb2f58d13 100644 --- a/src/core/hle/service/server_manager.h +++ b/src/core/hle/service/server_manager.h @@ -49,6 +49,7 @@ public: Result LoopProcess(); void StartAdditionalHostThreads(const char* name, size_t num_threads); + void NotifyShutdown(); static void RunServer(std::unique_ptr&& server);