From 3b639b604d9c7d7c01455ba7b71eece25e0e805c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 16 Apr 2020 05:18:31 -0700 Subject: [PATCH] pgl: Implement (Get)ShellEventObserver --- .../source/pgl/srv/pgl_srv_shell.cpp | 21 +++++ .../source/pgl/srv/pgl_srv_shell.hpp | 5 ++ .../pgl/srv/pgl_srv_shell_event_observer.cpp | 78 +++++++++++++++++++ .../pgl/srv/pgl_srv_shell_event_observer.hpp | 78 +++++++++++++++++++ .../pgl/srv/pgl_srv_shell_interface.cpp | 18 ++++- .../include/vapours/results/pgl_results.hpp | 1 + 6 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.cpp create mode 100644 libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.hpp diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp index b452481a7..5ae538539 100644 --- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.cpp @@ -15,6 +15,7 @@ */ #include #include "pgl_srv_shell.hpp" +#include "pgl_srv_shell_event_observer.hpp" namespace ams::pgl::srv { @@ -46,6 +47,9 @@ namespace ams::pgl::srv { os::ThreadType g_process_control_task_thread; alignas(os::ThreadStackAlignment) u8 g_process_control_task_stack[ProcessControlTaskStackSize]; + os::SdkMutex g_observer_list_mutex; + util::IntrusiveListBaseTraits::ListType g_observer_list; + os::SdkMutex g_process_data_mutex; ProcessData g_process_data[ProcessDataCount]; @@ -155,6 +159,23 @@ namespace ams::pgl::srv { os::StartThread(std::addressof(g_process_control_task_thread)); } + void RegisterShellEventObserver(ShellEventObserverHolder *holder) { + std::scoped_lock lk(g_observer_list_mutex); + + g_observer_list.push_back(*holder); + } + + void UnregisterShellEventObserver(ShellEventObserverHolder *holder) { + std::scoped_lock lk(g_observer_list_mutex); + + for (auto &observer : g_observer_list) { + if (std::addressof(observer) == holder) { + g_observer_list.erase(g_observer_list.iterator_to(observer)); + break; + } + } + } + Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags) { /* Convert the input flags to the internal format. */ const u32 data_flags = ConvertToProcessDataFlags(pgl_flags); diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp index 041b0f36e..f9c4c93d7 100644 --- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell.hpp @@ -20,6 +20,11 @@ namespace ams::pgl::srv { void InitializeProcessControlTask(); + class ShellEventObserverHolder; + + void RegisterShellEventObserver(ShellEventObserverHolder *holder); + void UnregisterShellEventObserver(ShellEventObserverHolder *holder); + Result LaunchProgram(os::ProcessId *out, const ncm::ProgramLocation &loc, u32 pm_flags, u8 pgl_flags); Result TerminateProcess(os::ProcessId process_id); Result GetApplicationProcessId(os::ProcessId *out); diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.cpp new file mode 100644 index 000000000..daaa1e0f5 --- /dev/null +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "pgl_srv_shell_event_observer.hpp" +#include "pgl_srv_shell.hpp" + +namespace ams::pgl::srv { + + ShellEventObserver::ShellEventObserver() : message_queue(queue_buffer, QueueCapacity), event(os::EventClearMode_AutoClear, true) { + this->heap_handle = lmem::CreateUnitHeap(this->event_info_data, sizeof(this->event_info_data), sizeof(this->event_info_data[0]), lmem::CreateOption_ThreadSafe, 8, GetPointer(this->heap_head)); + + new (GetPointer(this->holder)) ShellEventObserverHolder(this); + RegisterShellEventObserver(GetPointer(this->holder)); + } + + ShellEventObserver::~ShellEventObserver() { + UnregisterShellEventObserver(GetPointer(this->holder)); + GetReference(this->holder).~ShellEventObserverHolder(); + } + + Result ShellEventObserver::PopEventInfo(pm::ProcessEventInfo *out) { + /* Receive an info from the queue. */ + uintptr_t info_address; + R_UNLESS(this->message_queue.TryReceive(std::addressof(info_address)), pgl::ResultNotAvailable()); + pm::ProcessEventInfo *info = reinterpret_cast(info_address); + + /* Set the output. */ + *out = *info; + + /* Free the received info. */ + lmem::FreeToUnitHeap(this->heap_handle, info); + + return ResultSuccess(); + } + + void ShellEventObserver::Notify(const pm::ProcessEventInfo &info) { + /* Allocate a new info. */ + auto allocated = reinterpret_cast(lmem::AllocateFromUnitHeap(this->heap_handle)); + if (!allocated) { + return; + } + + /* Set it to the notification. */ + *allocated = info; + + /* Try to send it. */ + if (!this->message_queue.TrySend(reinterpret_cast(allocated))) { + lmem::FreeToUnitHeap(this->heap_handle, allocated); + return; + } + + /* Notify that we have a new info available. */ + this->event.Signal(); + } + + Result EventObserverInterface::GetProcessEventHandle(ams::sf::OutCopyHandle out) { + out.SetValue(GetReference(this->observer).GetEvent().GetReadableHandle()); + return ResultSuccess(); + } + + Result EventObserverInterface::GetProcessEventInfo(ams::sf::Out out) { + return GetReference(this->observer).PopEventInfo(out.GetPointer()); + } + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.hpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.hpp new file mode 100644 index 000000000..29918a8c3 --- /dev/null +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_event_observer.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018-2020 Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::pgl::srv { + + class IShellEventObserver { + public: + virtual void Notify(const pm::ProcessEventInfo &info) = 0; + }; + + class ShellEventObserverHolder : public util::IntrusiveListBaseNode { + private: + IShellEventObserver *observer; + public: + explicit ShellEventObserverHolder(IShellEventObserver *observer) : observer(observer) { /* ... */ } + + void Notify(const pm::ProcessEventInfo &info) { + this->observer->Notify(info); + } + }; + + class ShellEventObserver final : public IShellEventObserver { + private: + static constexpr size_t QueueCapacity = 0x20; + private: + os::MessageQueue message_queue; + uintptr_t queue_buffer[QueueCapacity]; + os::SystemEvent event; + TYPED_STORAGE(lmem::HeapCommonHead) heap_head; + lmem::HeapHandle heap_handle; + pm::ProcessEventInfo event_info_data[QueueCapacity]; + TYPED_STORAGE(ShellEventObserverHolder) holder; + public: + ShellEventObserver(); + ~ShellEventObserver(); + + os::SystemEvent &GetEvent() { + return this->event; + } + + Result PopEventInfo(pm::ProcessEventInfo *out); + + virtual void Notify(const pm::ProcessEventInfo &info) override final; + }; + + class EventObserverInterface final : public pgl::sf::IEventObserver { + private: + TYPED_STORAGE(ShellEventObserver) observer; + public: + EventObserverInterface() { + std::memset(std::addressof(this->observer), 0, sizeof(this->observer)); + new (GetPointer(this->observer)) ShellEventObserver; + } + + ~EventObserverInterface() { + GetReference(this->observer).~ShellEventObserver(); + } + public: + virtual Result GetProcessEventHandle(ams::sf::OutCopyHandle out) override final; + virtual Result GetProcessEventInfo(ams::sf::Out out) override final; + }; + +} diff --git a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp index 12c8bf044..c08d14b2f 100644 --- a/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp +++ b/libraries/libstratosphere/source/pgl/srv/pgl_srv_shell_interface.cpp @@ -15,6 +15,7 @@ */ #include #include "pgl_srv_shell.hpp" +#include "pgl_srv_shell_event_observer.hpp" namespace ams::pgl::srv { @@ -67,7 +68,22 @@ namespace ams::pgl::srv { } Result ShellInterface::GetShellEventObserver(ams::sf::Out> out) { - /* TODO */ + /* Allocate a new interface. */ + auto *observer_memory = this->memory_resource->Allocate(sizeof(EventObserverInterface), alignof(EventObserverInterface)); + AMS_ABORT_UNLESS(observer_memory != nullptr); + + /* Create the interface object. */ + new (observer_memory) EventObserverInterface; + + /* Set the output. */ + out.SetValue(std::shared_ptr(reinterpret_cast(observer_memory), [&](EventObserverInterface *obj) { + /* Destroy the object. */ + obj->~EventObserverInterface(); + + /* Custom deleter: use the memory resource to free. */ + this->memory_resource->Deallocate(obj, sizeof(EventObserverInterface), alignof(EventObserverInterface)); + })); + return ResultSuccess(); } } \ No newline at end of file diff --git a/libraries/libvapours/include/vapours/results/pgl_results.hpp b/libraries/libvapours/include/vapours/results/pgl_results.hpp index 7c6d2240c..93e4eb1a4 100644 --- a/libraries/libvapours/include/vapours/results/pgl_results.hpp +++ b/libraries/libvapours/include/vapours/results/pgl_results.hpp @@ -21,6 +21,7 @@ namespace ams::pgl { R_DEFINE_NAMESPACE_RESULT_MODULE(228); + R_DEFINE_ERROR_RESULT(NotAvailable, 2); R_DEFINE_ERROR_RESULT(ApplicationNotRunning, 3); R_DEFINE_ERROR_RESULT(BufferNotEnough, 4); R_DEFINE_ERROR_RESULT(ApplicationContentNotFound, 5);