am: activate event observer
This commit is contained in:
		| @@ -409,6 +409,8 @@ add_library(core STATIC | |||||||
|     hle/service/am/button_poller.h |     hle/service/am/button_poller.h | ||||||
|     hle/service/am/display_layer_manager.cpp |     hle/service/am/display_layer_manager.cpp | ||||||
|     hle/service/am/display_layer_manager.h |     hle/service/am/display_layer_manager.h | ||||||
|  |     hle/service/am/event_observer.cpp | ||||||
|  |     hle/service/am/event_observer.h | ||||||
|     hle/service/am/frontend/applet_cabinet.cpp |     hle/service/am/frontend/applet_cabinet.cpp | ||||||
|     hle/service/am/frontend/applet_cabinet.h |     hle/service/am/frontend/applet_cabinet.h | ||||||
|     hle/service/am/frontend/applet_controller.cpp |     hle/service/am/frontend/applet_controller.cpp | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ | |||||||
|  |  | ||||||
| #include "core/hle/service/am/am.h" | #include "core/hle/service/am/am.h" | ||||||
| #include "core/hle/service/am/button_poller.h" | #include "core/hle/service/am/button_poller.h" | ||||||
|  | #include "core/hle/service/am/event_observer.h" | ||||||
| #include "core/hle/service/am/service/all_system_applet_proxies_service.h" | #include "core/hle/service/am/service/all_system_applet_proxies_service.h" | ||||||
| #include "core/hle/service/am/service/application_proxy_service.h" | #include "core/hle/service/am/service/application_proxy_service.h" | ||||||
| #include "core/hle/service/server_manager.h" | #include "core/hle/service/server_manager.h" | ||||||
| @@ -11,6 +12,7 @@ namespace Service::AM { | |||||||
|  |  | ||||||
| void LoopProcess(Core::System& system) { | void LoopProcess(Core::System& system) { | ||||||
|     ButtonPoller button_poller(system); |     ButtonPoller button_poller(system); | ||||||
|  |     EventObserver event_observer(system); | ||||||
|  |  | ||||||
|     auto server_manager = std::make_unique<ServerManager>(system); |     auto server_manager = std::make_unique<ServerManager>(system); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										156
									
								
								src/core/hle/service/am/event_observer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								src/core/hle/service/am/event_observer.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,156 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #include "core/core.h" | ||||||
|  | #include "core/hle/kernel/k_event.h" | ||||||
|  | #include "core/hle/service/am/applet.h" | ||||||
|  | #include "core/hle/service/am/event_observer.h" | ||||||
|  |  | ||||||
|  | namespace Service::AM { | ||||||
|  |  | ||||||
|  | enum class UserDataTag : u32 { | ||||||
|  |     WakeupEvent, | ||||||
|  |     AppletProcess, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | EventObserver::EventObserver(Core::System& system) | ||||||
|  |     : m_system(system), m_context(system, "am:EventObserver"), m_wakeup_event(m_context), | ||||||
|  |       m_wakeup_holder(m_wakeup_event.GetHandle()) { | ||||||
|  |     m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent)); | ||||||
|  |     m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait)); | ||||||
|  |     m_thread = std::thread([&] { this->ThreadFunc(); }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | EventObserver::~EventObserver() { | ||||||
|  |     // Signal thread and wait for processing to finish. | ||||||
|  |     m_stop_source.request_stop(); | ||||||
|  |     m_wakeup_event.Signal(); | ||||||
|  |     m_thread.join(); | ||||||
|  |  | ||||||
|  |     // Free remaining owned sessions. | ||||||
|  |     auto it = m_process_holder_list.begin(); | ||||||
|  |     while (it != m_process_holder_list.end()) { | ||||||
|  |         // Get the holder. | ||||||
|  |         auto* const holder = std::addressof(*it); | ||||||
|  |  | ||||||
|  |         // Remove from the list. | ||||||
|  |         it = m_process_holder_list.erase(it); | ||||||
|  |  | ||||||
|  |         // Free the holder. | ||||||
|  |         delete holder; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::TrackAppletProcess(Applet& applet) { | ||||||
|  |     // Don't observe dummy processes. | ||||||
|  |     if (!applet.process->IsInitialized()) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Allocate new holder. | ||||||
|  |     auto* holder = new ProcessHolder(applet, *applet.process); | ||||||
|  |     holder->SetUserData(static_cast<uintptr_t>(UserDataTag::AppletProcess)); | ||||||
|  |  | ||||||
|  |     // Insert into list. | ||||||
|  |     { | ||||||
|  |         std::scoped_lock lk{m_lock}; | ||||||
|  |         m_process_holder_list.push_back(*holder); | ||||||
|  |         holder->LinkToMultiWait(std::addressof(m_deferred_wait_list)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Signal wakeup. | ||||||
|  |     m_wakeup_event.Signal(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::RequestUpdate() { | ||||||
|  |     m_wakeup_event.Signal(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::LinkDeferred() { | ||||||
|  |     std::scoped_lock lk{m_lock}; | ||||||
|  |     m_multi_wait.MoveAll(std::addressof(m_deferred_wait_list)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MultiWaitHolder* EventObserver::WaitSignaled() { | ||||||
|  |     while (true) { | ||||||
|  |         this->LinkDeferred(); | ||||||
|  |  | ||||||
|  |         // If we're done, return before we start waiting. | ||||||
|  |         if (m_stop_source.stop_requested()) { | ||||||
|  |             return nullptr; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         auto* selected = m_multi_wait.WaitAny(m_system.Kernel()); | ||||||
|  |         if (selected != std::addressof(m_wakeup_holder)) { | ||||||
|  |             // Unlink the process. | ||||||
|  |             selected->UnlinkFromMultiWait(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return selected; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::Process(MultiWaitHolder* holder) { | ||||||
|  |     switch (static_cast<UserDataTag>(holder->GetUserData())) { | ||||||
|  |     case UserDataTag::WakeupEvent: | ||||||
|  |         this->OnWakeupEvent(holder); | ||||||
|  |         break; | ||||||
|  |     case UserDataTag::AppletProcess: | ||||||
|  |         this->OnProcessEvent(static_cast<ProcessHolder*>(holder)); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         UNREACHABLE(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::OnWakeupEvent(MultiWaitHolder* holder) { | ||||||
|  |     m_wakeup_event.Clear(); | ||||||
|  |  | ||||||
|  |     // Perform recalculation. | ||||||
|  |     // TODO | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::OnProcessEvent(ProcessHolder* holder) { | ||||||
|  |     // Check process state. | ||||||
|  |     auto& process = holder->GetProcess(); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         std::scoped_lock lk{m_lock}; | ||||||
|  |         if (process.IsTerminated()) { | ||||||
|  |             // Destroy the holder. | ||||||
|  |             this->DestroyAppletProcessHolderLocked(holder); | ||||||
|  |         } else { | ||||||
|  |             // Reset signaled state. | ||||||
|  |             process.ResetSignal(); | ||||||
|  |  | ||||||
|  |             // Relink wakeup event. | ||||||
|  |             holder->LinkToMultiWait(std::addressof(m_deferred_wait_list)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Perform recalculation. | ||||||
|  |     // TODO | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::DestroyAppletProcessHolderLocked(ProcessHolder* holder) { | ||||||
|  |     // Remove from owned list. | ||||||
|  |     m_process_holder_list.erase(m_process_holder_list.iterator_to(*holder)); | ||||||
|  |  | ||||||
|  |     // Destroy and free. | ||||||
|  |     delete holder; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void EventObserver::ThreadFunc() { | ||||||
|  |     Common::SetCurrentThreadName("am:EventObserver"); | ||||||
|  |  | ||||||
|  |     while (true) { | ||||||
|  |         auto* signaled_holder = this->WaitSignaled(); | ||||||
|  |         if (!signaled_holder) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this->Process(signaled_holder); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace Service::AM | ||||||
							
								
								
									
										70
									
								
								src/core/hle/service/am/event_observer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/core/hle/service/am/event_observer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project | ||||||
|  | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "common/polyfill_thread.h" | ||||||
|  | #include "common/thread.h" | ||||||
|  | #include "core/hle/service/kernel_helpers.h" | ||||||
|  | #include "core/hle/service/os/event.h" | ||||||
|  | #include "core/hle/service/os/multi_wait.h" | ||||||
|  |  | ||||||
|  | namespace Core { | ||||||
|  | class System; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace Service::AM { | ||||||
|  |  | ||||||
|  | struct Applet; | ||||||
|  | class ProcessHolder; | ||||||
|  |  | ||||||
|  | class EventObserver { | ||||||
|  | public: | ||||||
|  |     explicit EventObserver(Core::System& system); | ||||||
|  |     ~EventObserver(); | ||||||
|  |  | ||||||
|  |     void TrackAppletProcess(Applet& applet); | ||||||
|  |     void RequestUpdate(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void LinkDeferred(); | ||||||
|  |     MultiWaitHolder* WaitSignaled(); | ||||||
|  |     void Process(MultiWaitHolder* holder); | ||||||
|  |     bool WaitAndProcessImpl(); | ||||||
|  |     void LoopProcess(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void OnWakeupEvent(MultiWaitHolder* holder); | ||||||
|  |     void OnProcessEvent(ProcessHolder* holder); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void DestroyAppletProcessHolderLocked(ProcessHolder* holder); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     void ThreadFunc(); | ||||||
|  |  | ||||||
|  | private: | ||||||
|  |     // System reference and context. | ||||||
|  |     Core::System& m_system; | ||||||
|  |     KernelHelpers::ServiceContext m_context; | ||||||
|  |  | ||||||
|  |     // Guest event handle to wake up the event loop processor. | ||||||
|  |     Event m_wakeup_event; | ||||||
|  |     MultiWaitHolder m_wakeup_holder; | ||||||
|  |  | ||||||
|  |     // Mutex to protect remaining members. | ||||||
|  |     std::mutex m_lock{}; | ||||||
|  |  | ||||||
|  |     // List of owned process holders. | ||||||
|  |     Common::IntrusiveListBaseTraits<ProcessHolder>::ListType m_process_holder_list; | ||||||
|  |  | ||||||
|  |     // Multi-wait objects for new tasks. | ||||||
|  |     MultiWait m_multi_wait; | ||||||
|  |     MultiWait m_deferred_wait_list; | ||||||
|  |  | ||||||
|  |     // Processing thread. | ||||||
|  |     std::thread m_thread{}; | ||||||
|  |     std::stop_source m_stop_source{}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace Service::AM | ||||||
| @@ -13,7 +13,7 @@ namespace Service::AM { | |||||||
|  |  | ||||||
| struct Applet; | struct Applet; | ||||||
|  |  | ||||||
| class ProcessHolder : public MultiWaitHolder { | class ProcessHolder : public MultiWaitHolder, public Common::IntrusiveListBaseNode<ProcessHolder> { | ||||||
| public: | public: | ||||||
|     explicit ProcessHolder(Applet& applet, Process& process); |     explicit ProcessHolder(Applet& applet, Process& process); | ||||||
|     ~ProcessHolder(); |     ~ProcessHolder(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Liam
					Liam