diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_event_handler_manager.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_event_handler_manager.hpp index 1b3070b..0c86fd9 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_event_handler_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_event_handler_manager.hpp @@ -31,10 +31,10 @@ bool is_initialized; bool is_looping; os::SdkConditionVariable is_looping_cv; - os::WaitableManagerType waitable_manager; + os::MultiWaitType multi_wait; os::ThreadType *loop_thread; os::Event loop_control_event; - os::WaitableHolderType loop_control_event_holder; + os::MultiWaitHolderType loop_control_event_holder; LoopControlCommandParameters *loop_control_command_params; os::LightEvent loop_control_command_done_event; os::SdkMutex loop_control_lock; @@ -43,7 +43,7 @@ void ProcessControlCommandImpl(LoopControlCommandParameters *params); public: EventHandlerManager() - : is_initialized(false), is_looping(false), is_looping_cv(), waitable_manager(), + : is_initialized(false), is_looping(false), is_looping_cv(), multi_wait(), loop_thread(), loop_control_event(os::EventClearMode_AutoClear), loop_control_event_holder(), loop_control_command_params(), loop_control_command_done_event(os::EventClearMode_AutoClear), loop_control_lock() diff --git a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp index 4d85f14..efe34b3 100644 --- a/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp +++ b/libraries/libstratosphere/include/stratosphere/ddsf/ddsf_i_event_handler.hpp @@ -26,27 +26,27 @@ NON_MOVEABLE(IEventHandler); friend class EventHandlerManager; private: - os::WaitableHolderType holder; + os::MultiWaitHolderType holder; uintptr_t user_data; bool is_initialized; bool is_registered; private: - void Link(os::WaitableManagerType *manager) { + void Link(os::MultiWaitType *multi_wait) { AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(!this->IsRegistered()); - AMS_ASSERT(manager != nullptr); - os::LinkWaitableHolder(manager, std::addressof(this->holder)); + AMS_ASSERT(multi_wait != nullptr); + os::LinkMultiWaitHolder(multi_wait, std::addressof(this->holder)); } void Unlink() { AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(this->IsRegistered()); - os::UnlinkWaitableHolder(std::addressof(this->holder)); + os::UnlinkMultiWaitHolder(std::addressof(this->holder)); } - static IEventHandler &ToEventHandler(os::WaitableHolderType *holder) { + static IEventHandler &ToEventHandler(os::MultiWaitHolderType *holder) { AMS_ASSERT(holder != nullptr); - auto &event_handler = *reinterpret_cast(os::GetWaitableHolderUserData(holder)); + auto &event_handler = *reinterpret_cast(os::GetMultiWaitHolderUserData(holder)); AMS_ASSERT(event_handler.IsInitialized()); return event_handler; } @@ -72,8 +72,8 @@ void Initialize(T *object) { AMS_ASSERT(object != nullptr); AMS_ASSERT(!this->IsInitialized()); - os::InitializeWaitableHolder(std::addressof(this->holder), object); - os::SetWaitableHolderUserData(std::addressof(this->holder), reinterpret_cast(this)); + os::InitializeMultiWaitHolder(std::addressof(this->holder), object); + os::SetMultiWaitHolderUserData(std::addressof(this->holder), reinterpret_cast(this)); this->is_initialized = true; this->is_registered = false; } @@ -81,7 +81,7 @@ void Finalize() { AMS_ASSERT(this->IsInitialized()); AMS_ASSERT(!this->IsRegistered()); - os::FinalizeWaitableHolder(std::addressof(this->holder)); + os::FinalizeMultiWaitHolder(std::addressof(this->holder)); this->is_initialized = false; this->is_registered = false; } diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 5ce3c25..6e94c65 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -50,4 +50,4 @@ #include #include #include -#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_event_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_event_api.hpp index 0f7b750..804a3ac 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_event_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_event_api.hpp @@ -21,7 +21,7 @@ namespace ams::os { struct EventType; - struct WaitableHolderType; + struct MultiWaitHolderType; void InitializeEvent(EventType *event, bool signaled, EventClearMode clear_mode); void FinalizeEvent(EventType *event); @@ -32,6 +32,6 @@ bool TimedWaitEvent(EventType *event, TimeSpan timeout); void ClearEvent(EventType *event); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, EventType *event); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, EventType *event); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_event_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_event_types.hpp index 7b61a5c..9f73ecc 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_event_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_event_types.hpp @@ -23,7 +23,7 @@ namespace impl { - class WaitableObjectList; + class MultiWaitObjectList; } @@ -33,7 +33,7 @@ State_Initialized = 1, }; - util::TypedStorage waitable_object_list_storage; + util::TypedStorage multi_wait_object_list_storage; bool signaled; bool initially_signaled; u8 clear_mode; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp index b2dcf79..68e265c 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_api.hpp @@ -21,7 +21,7 @@ namespace ams::os { struct InterruptEventType; - struct WaitableHolderType; + struct MultiWaitHolderType; void InitializeInterruptEvent(InterruptEventType *event, InterruptName name, EventClearMode clear_mode); void FinalizeInterruptEvent(InterruptEventType *event); @@ -31,6 +31,6 @@ bool TimedWaitInterruptEvent(InterruptEventType *event, TimeSpan timeout); void ClearInterruptEvent(InterruptEventType *event); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, InterruptEventType *event); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_types.hpp index 6858320..d9d2d17 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_interrupt_event_types.hpp @@ -23,7 +23,7 @@ namespace impl { - class WaitableObjectList; + class MultiWaitObjectList; class InterruptEventImpl; } @@ -34,7 +34,7 @@ State_Initialized = 1, }; - util::TypedStorage waitable_object_list_storage; + util::TypedStorage multi_wait_object_list_storage; u8 clear_mode; u8 state; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_message_queue_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_message_queue_api.hpp index 0f772a4..576ea23 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_message_queue_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_message_queue_api.hpp @@ -21,7 +21,7 @@ namespace ams::os { struct MessageQueueType; - struct WaitableHolderType; + struct MultiWaitHolderType; void InitializeMessageQueue(MessageQueueType *mq, uintptr_t *buffer, size_t count); void FinalizeMessageQueue(MessageQueueType *mq); @@ -46,6 +46,6 @@ bool TryPeekMessageQueue(uintptr_t *out, const MessageQueueType *mq); bool TimedPeekMessageQueue(uintptr_t *out, const MessageQueueType *mq, TimeSpan timeout); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, MessageQueueType *event, MessageQueueWaitType wait_type); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, MessageQueueType *event, MessageQueueWaitType wait_type); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_message_queue_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_message_queue_types.hpp index 7c7789c..1542aa5 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_message_queue_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_message_queue_types.hpp @@ -23,7 +23,7 @@ namespace impl { - class WaitableObjectList; + class MultiWaitObjectList; } @@ -33,8 +33,8 @@ State_Initialized = 1, }; - util::TypedStorage waitlist_not_full; - util::TypedStorage waitlist_not_empty; + util::TypedStorage waitlist_not_full; + util::TypedStorage waitlist_not_empty; uintptr_t *buffer; s32 capacity; s32 count; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait.hpp b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait.hpp new file mode 100644 index 0000000..bbb1c19 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait.hpp @@ -0,0 +1,19 @@ +/* + * 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 +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_api.hpp new file mode 100644 index 0000000..7f9c421 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_api.hpp @@ -0,0 +1,45 @@ +/* + * 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 +#include + +namespace ams::os { + + struct MultiWaitHolderType; + struct MultiWaitType; + + void InitializeMultiWait(MultiWaitType *multi_wait); + void FinalizeMultiWait(MultiWaitType *multi_wait); + + MultiWaitHolderType *WaitAny(MultiWaitType *multi_wait); + MultiWaitHolderType *TryWaitAny(MultiWaitType *multi_wait); + MultiWaitHolderType *TimedWaitAny(MultiWaitType *multi_wait, TimeSpan timeout); + + void FinalizeMultiWaitHolder(MultiWaitHolderType *holder); + + void LinkMultiWaitHolder(MultiWaitType *multi_wait, MultiWaitHolderType *holder); + void UnlinkMultiWaitHolder(MultiWaitHolderType *holder); + void UnlinkAllMultiWaitHolder(MultiWaitType *multi_wait); + + void MoveAllMultiWaitHolder(MultiWaitType *dst, MultiWaitType *src); + + void SetMultiWaitHolderUserData(MultiWaitHolderType *holder, uintptr_t user_data); + uintptr_t GetMultiWaitHolderUserData(const MultiWaitHolderType *holder); + + void InitializeMultiWaitHolder(MultiWaitHolderType *holder, Handle handle); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp new file mode 100644 index 0000000..48ccbc2 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_types.hpp @@ -0,0 +1,47 @@ +/* + * 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 +#include + +namespace ams::os { + + namespace impl { + + class MultiWaitImpl; + struct MultiWaitHolderImpl; + + } + + struct MultiWaitType { + enum State { + State_NotInitialized, + State_Initialized, + }; + + u8 state; + bool is_waiting; + util::TypedStorage impl_storage; + }; + static_assert(std::is_trivial::value); + + struct MultiWaitHolderType { + util::TypedStorage impl_storage; + uintptr_t user_data; + }; + static_assert(std::is_trivial::value); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_utils.hpp b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_utils.hpp new file mode 100644 index 0000000..a0612d1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_multiple_wait_utils.hpp @@ -0,0 +1,124 @@ +/* + * 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 +#include +#include +#include + +namespace ams::os { + + namespace impl { + + class AutoMultiWaitHolder { + private: + MultiWaitHolderType m_holder; + public: + template + ALWAYS_INLINE explicit AutoMultiWaitHolder(MultiWaitType *multi_wait, T &&arg) { + InitializeMultiWaitHolder(std::addressof(m_holder), std::forward(arg)); + LinkMultiWaitHolder(multi_wait, std::addressof(m_holder)); + } + + ALWAYS_INLINE ~AutoMultiWaitHolder() { + UnlinkMultiWaitHolder(std::addressof(m_holder)); + FinalizeMultiWaitHolder(std::addressof(m_holder)); + } + + ALWAYS_INLINE std::pair ConvertResult(const std::pair result, int index) { + if (result.first == std::addressof(m_holder)) { + return std::make_pair(static_cast(nullptr), index); + } else { + return result; + } + } + }; + + template + inline std::pair WaitAnyImpl(F &&func, MultiWaitType *multi_wait, int) { + return std::pair(func(multi_wait), -1); + } + + template + inline std::pair WaitAnyImpl(F &&func, MultiWaitType *multi_wait, int index, T &&x, Args &&... args) { + AutoMultiWaitHolder holder(multi_wait, std::forward(x)); + return holder.ConvertResult(WaitAnyImpl(std::forward(func), multi_wait, index + 1, std::forward(args)...), index); + } + + template + inline std::pair WaitAnyImpl(F &&func, MultiWaitType *multi_wait, Args &&... args) { + return WaitAnyImpl(std::forward(func), multi_wait, 0, std::forward(args)...); + } + + class TempMultiWait { + private: + MultiWaitType m_multi_wait; + public: + ALWAYS_INLINE TempMultiWait() { + os::InitializeMultiWait(std::addressof(m_multi_wait)); + } + + ALWAYS_INLINE ~TempMultiWait() { + os::FinalizeMultiWait(std::addressof(m_multi_wait)); + } + + MultiWaitType *Get() { + return std::addressof(m_multi_wait); + } + }; + + template + inline std::pair WaitAnyImpl(F &&func, Args &&... args) { + TempMultiWait temp_multi_wait; + return WaitAnyImpl(std::forward(func), temp_multi_wait.Get(), 0, std::forward(args)...); + } + + using WaitAnyFunction = MultiWaitHolderType * (*)(MultiWaitType *); + + class NotBoolButInt { + private: + int m_value; + public: + constexpr ALWAYS_INLINE NotBoolButInt(int v) : m_value(v) { /* ... */ } + + constexpr ALWAYS_INLINE operator int() const { return m_value; } + + explicit operator bool() const = delete; + }; + + } + + template requires (sizeof...(Args) > 0) + inline std::pair WaitAny(MultiWaitType *multi_wait, Args &&... args) { + return impl::WaitAnyImpl(static_cast(&::ams::os::WaitAny), multi_wait, std::forward(args)...); + } + + template requires (sizeof...(Args) > 0) + inline int WaitAny(Args &&... args) { + return impl::WaitAnyImpl(static_cast(&::ams::os::WaitAny), std::forward(args)...).second; + } + + template requires (sizeof...(Args) > 0) + inline std::pair TryWaitAny(MultiWaitType *multi_wait, Args &&... args) { + return impl::WaitAnyImpl(static_cast(&::ams::os::TryWaitAny), multi_wait, std::forward(args)...); + } + + template requires (sizeof...(Args) > 0) + inline impl::NotBoolButInt TryWaitAny(Args &&... args) { + return impl::WaitAnyImpl(static_cast(&::ams::os::TryWaitAny), std::forward(args)...).second; + } + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_reply_and_receive.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_reply_and_receive.hpp index a88967c..3ed8c49 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_sdk_reply_and_receive.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_reply_and_receive.hpp @@ -18,9 +18,9 @@ namespace ams::os { - struct WaitableHolderType; - struct WaitableManagerType; + struct MultiWaitHolderType; + struct MultiWaitType; - Result SdkReplyAndReceive(os::WaitableHolderType **out, Handle reply_target, WaitableManagerType *manager); + Result SdkReplyAndReceive(os::MultiWaitHolderType **out, Handle reply_target, MultiWaitType *multi_wait); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_semaphore_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_semaphore_api.hpp index bd76191..79ac7c4 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_semaphore_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_semaphore_api.hpp @@ -20,7 +20,7 @@ namespace ams::os { struct SemaphoreType; - struct WaitableHolderType; + struct MultiWaitHolderType; void InitializeSemaphore(SemaphoreType *sema, s32 count, s32 max_count); void FinalizeSemaphore(SemaphoreType *sema); @@ -34,6 +34,6 @@ s32 GetCurrentSemaphoreCount(const SemaphoreType *sema); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, SemaphoreType *sema); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, SemaphoreType *sema); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_semaphore_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_semaphore_types.hpp index 1287366..8168ece 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_semaphore_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_semaphore_types.hpp @@ -23,7 +23,7 @@ namespace impl { - class WaitableObjectList; + class MultiWaitObjectList; } @@ -33,7 +33,7 @@ State_Initialized = 1, }; - util::TypedStorage waitlist; + util::TypedStorage waitlist; u8 state; s32 count; s32 max_count; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_system_event_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_system_event_api.hpp index d31c0e0..837c3ff 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_system_event_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_system_event_api.hpp @@ -21,7 +21,7 @@ namespace ams::os { struct SystemEventType; - struct WaitableHolderType; + struct MultiWaitHolderType; Result CreateSystemEvent(SystemEventType *event, EventClearMode clear_mode, bool inter_process); void DestroySystemEvent(SystemEventType *event); @@ -42,6 +42,6 @@ bool TimedWaitSystemEvent(SystemEventType *event, TimeSpan timeout); void ClearSystemEvent(SystemEventType *event); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, SystemEventType *event); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, SystemEventType *event); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_system_event_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_system_event_types.hpp index cff31bc..3239421 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_system_event_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_system_event_types.hpp @@ -28,7 +28,7 @@ State_Initialized = 1, }; - util::TypedStorage waitable_object_list_storage; + util::TypedStorage multi_wait_object_list_storage; bool auto_clear; u8 state; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp index 3d7c421..b2ec9a4 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_thread_api.hpp @@ -21,7 +21,7 @@ namespace ams::os { struct ThreadType; - struct WaitableHolderType; + struct MultiWaitHolderType; Result CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority, s32 ideal_core); Result CreateThread(ThreadType *thread, ThreadFunction function, void *argument, void *stack, size_t stack_size, s32 priority); @@ -62,6 +62,6 @@ ThreadId GetThreadId(const ThreadType *thread); - void InitializeWaitableHolder(WaitableHolderType *holder, ThreadType *thread); + void InitializeMultiWaitHolder(MultiWaitHolderType *holder, ThreadType *thread); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp index a0662fd..9a9a3ef 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_thread_types.hpp @@ -26,7 +26,7 @@ namespace impl { - class WaitableObjectList; + class MultiWaitObjectList; } @@ -47,7 +47,7 @@ }; util::TypedStorage all_threads_node; - util::TypedStorage waitlist; + util::TypedStorage waitlist; uintptr_t reserved[4]; u8 state; u8 suspend_count; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_timer_event_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_timer_event_api.hpp index 40d58ef..c9e6106 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_timer_event_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_timer_event_api.hpp @@ -21,7 +21,7 @@ namespace ams::os { struct TimerEventType; - struct WaitableHolderType; + struct MultiWaitHolderType; void InitializeTimerEvent(TimerEventType *event, EventClearMode clear_mode); void FinalizeTimerEvent(TimerEventType *event); @@ -36,6 +36,6 @@ void SignalTimerEvent(TimerEventType *event); void ClearTimerEvent(TimerEventType *event); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, TimerEventType *event); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, TimerEventType *event); } diff --git a/libraries/libstratosphere/include/stratosphere/os/os_timer_event_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_timer_event_types.hpp index 975445d..652c0ad 100644 --- a/libraries/libstratosphere/include/stratosphere/os/os_timer_event_types.hpp +++ b/libraries/libstratosphere/include/stratosphere/os/os_timer_event_types.hpp @@ -24,7 +24,7 @@ namespace impl { - class WaitableObjectList; + class MultiWaitObjectList; } @@ -42,7 +42,7 @@ TimerState_Periodic = 2, }; - util::TypedStorage waitable_object_list_storage; + util::TypedStorage multi_wait_object_list_storage; u8 state; u8 clear_mode; diff --git a/libraries/libstratosphere/include/stratosphere/os/os_waitable.hpp b/libraries/libstratosphere/include/stratosphere/os/os_waitable.hpp deleted file mode 100644 index 13fa5c9..0000000 --- a/libraries/libstratosphere/include/stratosphere/os/os_waitable.hpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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 -#include -#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_waitable_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_waitable_api.hpp deleted file mode 100644 index 2ede0d9..0000000 --- a/libraries/libstratosphere/include/stratosphere/os/os_waitable_api.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 -#include - -namespace ams::os { - - struct WaitableHolderType; - struct WaitableManagerType; - - void InitializeWaitableManager(WaitableManagerType *manager); - void FinalizeWaitableManager(WaitableManagerType *manager); - - WaitableHolderType *WaitAny(WaitableManagerType *manager); - WaitableHolderType *TryWaitAny(WaitableManagerType *manager); - WaitableHolderType *TimedWaitAny(WaitableManagerType *manager, TimeSpan timeout); - - void FinalizeWaitableHolder(WaitableHolderType *holder); - - void LinkWaitableHolder(WaitableManagerType *manager, WaitableHolderType *holder); - void UnlinkWaitableHolder(WaitableHolderType *holder); - void UnlinkAllWaitableHolder(WaitableManagerType *manager); - - void MoveAllWaitableHolder(WaitableManagerType *dst, WaitableManagerType *src); - - void SetWaitableHolderUserData(WaitableHolderType *holder, uintptr_t user_data); - uintptr_t GetWaitableHolderUserData(const WaitableHolderType *holder); - - void InitializeWaitableHolder(WaitableHolderType *holder, Handle handle); - -} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_waitable_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_waitable_types.hpp deleted file mode 100644 index d4aa47f..0000000 --- a/libraries/libstratosphere/include/stratosphere/os/os_waitable_types.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 -#include - -namespace ams::os { - - namespace impl { - - class WaitableManagerImpl; - struct WaitableHolderImpl; - - } - - struct WaitableManagerType { - enum State { - State_NotInitialized, - State_Initialized, - }; - - u8 state; - bool is_waiting; - util::TypedStorage impl_storage; - }; - static_assert(std::is_trivial::value); - - struct WaitableHolderType { - util::TypedStorage impl_storage; - uintptr_t user_data; - }; - static_assert(std::is_trivial::value); - -} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_waitable_utils.hpp b/libraries/libstratosphere/include/stratosphere/os/os_waitable_utils.hpp deleted file mode 100644 index 6cfd5ab..0000000 --- a/libraries/libstratosphere/include/stratosphere/os/os_waitable_utils.hpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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 -#include -#include -#include - -namespace ams::os { - - namespace impl { - - class AutoWaitableHolder { - private: - WaitableHolderType m_holder; - public: - template - ALWAYS_INLINE explicit AutoWaitableHolder(WaitableManagerType *manager, T &&arg) { - InitializeWaitableHolder(std::addressof(m_holder), std::forward(arg)); - LinkWaitableHolder(manager, std::addressof(m_holder)); - } - - ALWAYS_INLINE ~AutoWaitableHolder() { - UnlinkWaitableHolder(std::addressof(m_holder)); - FinalizeWaitableHolder(std::addressof(m_holder)); - } - - ALWAYS_INLINE std::pair ConvertResult(const std::pair result, int index) { - if (result.first == std::addressof(m_holder)) { - return std::make_pair(static_cast(nullptr), index); - } else { - return result; - } - } - }; - - template - inline std::pair WaitAnyImpl(F &&func, WaitableManagerType *manager, int) { - return std::pair(func(manager), -1); - } - - template - inline std::pair WaitAnyImpl(F &&func, WaitableManagerType *manager, int index, T &&x, Args &&... args) { - AutoWaitableHolder holder(manager, std::forward(x)); - return holder.ConvertResult(WaitAnyImpl(std::forward(func), manager, index + 1, std::forward(args)...), index); - } - - template - inline std::pair WaitAnyImpl(F &&func, WaitableManagerType *manager, Args &&... args) { - return WaitAnyImpl(std::forward(func), manager, 0, std::forward(args)...); - } - - class TempWaitableManager { - private: - WaitableManagerType m_manager; - public: - ALWAYS_INLINE TempWaitableManager() { - os::InitializeWaitableManager(std::addressof(m_manager)); - } - - ALWAYS_INLINE ~TempWaitableManager() { - os::FinalizeWaitableManager(std::addressof(m_manager)); - } - - WaitableManagerType *Get() { - return std::addressof(m_manager); - } - }; - - template - inline std::pair WaitAnyImpl(F &&func, Args &&... args) { - TempWaitableManager temp_manager; - return WaitAnyImpl(std::forward(func), temp_manager.Get(), 0, std::forward(args)...); - } - - using WaitAnyFunction = WaitableHolderType * (*)(WaitableManagerType *); - - class NotBoolButInt { - private: - int m_value; - public: - constexpr ALWAYS_INLINE NotBoolButInt(int v) : m_value(v) { /* ... */ } - - constexpr ALWAYS_INLINE operator int() const { return m_value; } - - explicit operator bool() const = delete; - }; - - } - - template requires (sizeof...(Args) > 0) - inline std::pair WaitAny(WaitableManagerType *manager, Args &&... args) { - return impl::WaitAnyImpl(static_cast(&::ams::os::WaitAny), manager, std::forward(args)...); - } - - template requires (sizeof...(Args) > 0) - inline int WaitAny(Args &&... args) { - return impl::WaitAnyImpl(static_cast(&::ams::os::WaitAny), std::forward(args)...).second; - } - - template requires (sizeof...(Args) > 0) - inline std::pair TryWaitAny(WaitableManagerType *manager, Args &&... args) { - return impl::WaitAnyImpl(static_cast(&::ams::os::TryWaitAny), manager, std::forward(args)...); - } - - template requires (sizeof...(Args) > 0) - inline impl::NotBoolButInt TryWaitAny(Args &&... args) { - return impl::WaitAnyImpl(static_cast(&::ams::os::TryWaitAny), std::forward(args)...).second; - } - -} diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp index 0b7c501..dfb20cc 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_api.hpp @@ -28,8 +28,8 @@ NeedsRetry, }; - void AttachWaitableHolderForAccept(os::WaitableHolderType *holder, Handle port); - void AttachWaitableHolderForReply(os::WaitableHolderType *holder, Handle request); + void AttachMultiWaitHolderForAccept(os::MultiWaitHolderType *holder, Handle port); + void AttachMultiWaitHolderForReply(os::MultiWaitHolderType *holder, Handle request); Result Receive(ReceiveResult *out_recv_result, Handle session_handle, const cmif::PointerAndSize &message_buffer); Result Receive(bool *out_closed, Handle session_handle, const cmif::PointerAndSize &message_buffer); diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp index 0f1b2e4..a50792e 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_manager.hpp @@ -47,7 +47,7 @@ using ServerDomainSessionManager::DomainEntryStorage; using ServerDomainSessionManager::DomainStorage; protected: - class Server : public os::WaitableHolderType { + class Server : public os::MultiWaitHolderType { friend class ServerManagerBase; template friend class ServerManager; @@ -73,42 +73,42 @@ } }; private: - /* Management of waitables. */ - os::WaitableManagerType waitable_manager; + /* Multiple wait management. */ + os::MultiWaitType multi_wait; os::Event request_stop_event; - os::WaitableHolderType request_stop_event_holder; + os::MultiWaitHolderType request_stop_event_holder; os::Event notify_event; - os::WaitableHolderType notify_event_holder; + os::MultiWaitHolderType notify_event_holder; - os::SdkMutex waitable_selection_mutex; + os::SdkMutex selection_mutex; - os::SdkMutex waitlist_mutex; - os::WaitableManagerType waitlist; + os::SdkMutex deferred_list_mutex; + os::MultiWaitType deferred_list; private: - virtual void RegisterSessionToWaitList(ServerSession *session) override final; - void RegisterToWaitList(os::WaitableHolderType *holder); - void ProcessWaitList(); + virtual void RegisterServerSessionToWait(ServerSession *session) override final; + void LinkToDeferredList(os::MultiWaitHolderType *holder); + void LinkDeferred(); bool WaitAndProcessImpl(); - Result ProcessForServer(os::WaitableHolderType *holder); - Result ProcessForMitmServer(os::WaitableHolderType *holder); - Result ProcessForSession(os::WaitableHolderType *holder); + Result ProcessForServer(os::MultiWaitHolderType *holder); + Result ProcessForMitmServer(os::MultiWaitHolderType *holder); + Result ProcessForSession(os::MultiWaitHolderType *holder); void RegisterServerImpl(Server *server, Handle port_handle, bool is_mitm_server) { server->port_handle = port_handle; - hipc::AttachWaitableHolderForAccept(server, port_handle); + hipc::AttachMultiWaitHolderForAccept(server, port_handle); server->is_mitm_server = is_mitm_server; if (is_mitm_server) { /* Mitm server. */ - os::SetWaitableHolderUserData(server, static_cast(UserDataTag::MitmServer)); + os::SetMultiWaitHolderUserData(server, static_cast(UserDataTag::MitmServer)); } else { /* Non-mitm server. */ - os::SetWaitableHolderUserData(server, static_cast(UserDataTag::Server)); + os::SetMultiWaitHolderUserData(server, static_cast(UserDataTag::Server)); } - os::LinkWaitableHolder(std::addressof(this->waitable_manager), server); + os::LinkMultiWaitHolder(std::addressof(this->multi_wait), server); } void RegisterServerImpl(int index, cmif::ServiceObjectHolder &&static_holder, Handle port_handle, bool is_mitm_server) { @@ -192,15 +192,16 @@ ServerManagerBase(DomainEntryStorage *entry_storage, size_t entry_count) : ServerDomainSessionManager(entry_storage, entry_count), request_stop_event(os::EventClearMode_ManualClear), notify_event(os::EventClearMode_ManualClear), - waitable_selection_mutex(), waitlist_mutex() + selection_mutex(), deferred_list_mutex() { - /* Link waitables. */ - os::InitializeWaitableManager(std::addressof(this->waitable_manager)); - os::InitializeWaitableHolder(std::addressof(this->request_stop_event_holder), this->request_stop_event.GetBase()); - os::LinkWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->request_stop_event_holder)); - os::InitializeWaitableHolder(std::addressof(this->notify_event_holder), this->notify_event.GetBase()); - os::LinkWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->notify_event_holder)); - os::InitializeWaitableManager(std::addressof(this->waitlist)); + /* Link multi-wait holders. */ + os::InitializeMultiWait(std::addressof(this->multi_wait)); + os::InitializeMultiWaitHolder(std::addressof(this->request_stop_event_holder), this->request_stop_event.GetBase()); + os::LinkMultiWaitHolder(std::addressof(this->multi_wait), std::addressof(this->request_stop_event_holder)); + os::InitializeMultiWaitHolder(std::addressof(this->notify_event_holder), this->notify_event.GetBase()); + os::LinkMultiWaitHolder(std::addressof(this->multi_wait), std::addressof(this->notify_event_holder)); + + os::InitializeMultiWait(std::addressof(this->deferred_list)); } template @@ -227,13 +228,13 @@ } /* Processing. */ - os::WaitableHolderType *WaitSignaled(); + os::MultiWaitHolderType *WaitSignaled(); void ResumeProcessing(); void RequestStopProcessing(); - void AddUserWaitableHolder(os::WaitableHolderType *waitable); + void AddUserMultiWaitHolder(os::MultiWaitHolderType *holder); - Result Process(os::WaitableHolderType *waitable); + Result Process(os::MultiWaitHolderType *holder); void WaitAndProcess(); void LoopProcess(); }; @@ -324,8 +325,8 @@ const size_t index = this->GetServerIndex(server); AMS_ABORT_UNLESS(this->server_allocated[index]); { - os::UnlinkWaitableHolder(server); - os::FinalizeWaitableHolder(server); + os::UnlinkMultiWaitHolder(server); + os::FinalizeMultiWaitHolder(server); if (server->service_managed) { if (server->is_mitm_server) { R_ABORT_UNLESS(sm::mitm::UninstallMitm(server->service_name)); diff --git a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp index 7d9f4e4..72778b4 100644 --- a/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/sf/hipc/sf_hipc_server_session_manager.hpp @@ -38,7 +38,7 @@ } - class ServerSession : public os::WaitableHolderType { + class ServerSession : public os::MultiWaitHolderType { friend class ServerSessionManager; friend class ServerManagerBase; friend class impl::HipcManagerImpl; @@ -54,7 +54,7 @@ bool has_received; public: ServerSession(Handle h, cmif::ServiceObjectHolder &&obj) : srv_obj_holder(std::move(obj)), session_handle(h) { - hipc::AttachWaitableHolderForReply(this, h); + hipc::AttachMultiWaitHolderForReply(this, h); this->is_closed = false; this->has_received = false; this->forward_service = nullptr; @@ -62,7 +62,7 @@ } ServerSession(Handle h, cmif::ServiceObjectHolder &&obj, std::shared_ptr<::Service> &&fsrv) : srv_obj_holder(std::move(obj)), session_handle(h) { - hipc::AttachWaitableHolderForReply(this, h); + hipc::AttachMultiWaitHolderForReply(this, h); this->is_closed = false; this->has_received = false; this->forward_service = std::move(fsrv); @@ -105,7 +105,7 @@ void DestroySession(ServerSession *session); Result ProcessRequestImpl(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); - virtual void RegisterSessionToWaitList(ServerSession *session) = 0; + virtual void RegisterServerSessionToWait(ServerSession *session) = 0; protected: Result DispatchRequest(cmif::ServiceObjectHolder &&obj, ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); virtual Result DispatchManagerRequest(ServerSession *session, const cmif::PointerAndSize &in_message, const cmif::PointerAndSize &out_message); diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp new file mode 100644 index 0000000..dff3f96 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_holder.hpp @@ -0,0 +1,92 @@ +/* + * 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 +#include +#include + +namespace ams::tipc { + + class ObjectHolder { + public: + enum ObjectType : u8 { + ObjectType_Invalid = 0, + ObjectType_Port = 1, + ObjectType_Session = 2, + }; + private: + svc::Handle m_handle; + ObjectType m_type; + bool m_managed; + tipc::ServiceObjectBase *m_object; + private: + void InitializeImpl(ObjectType type, svc::Handle handle, bool managed, tipc::ServiceObjectBase *object) { + /* Validate that the object isn't already constructed. */ + AMS_ASSERT(m_type == ObjectType_Invalid); + + /* Set all fields. */ + m_handle = handle; + m_type = type; + m_managed = managed; + m_object = object; + } + public: + constexpr inline ObjectHolder() : m_handle(svc::InvalidHandle), m_type(ObjectType_Invalid), m_managed(false), m_object(nullptr) { /* ... */ } + + void InitializeAsPort(svc::Handle handle) { + /* NOTE: Nintendo sets ports as managed, but this will cause a nullptr-deref if one is ever closed. */ + /* This is theoretically a non-issue, as ports can't be closed, but we will set ours as unmanaged, */ + /* just in case. */ + this->InitializeImpl(ObjectType_Port, handle, false, nullptr); + } + + void InitializeAsSession(svc::Handle handle, bool managed, tipc::ServiceObjectBase *object) { + this->InitializeImpl(ObjectType_Session, handle, managed, object); + } + + void Destroy() { + /* Validate that the object is constructed. */ + AMS_ASSERT(m_type != ObjectType_Invalid); + + /* If we're managed, destroy the associated object. */ + if (m_managed) { + if (auto * const deleter = m_object->GetDeleter(); deleter != nullptr) { + deleter->DeleteServiceObject(m_object); + } + } + + /* Reset all fields. */ + m_handle = svc::InvalidHandle; + m_type = ObjectType_Invalid; + m_managed = false; + m_object = nullptr; + } + + constexpr svc::Handle GetHandle() const { + return m_handle; + } + + constexpr ObjectType GetType() const { + return m_type; + } + + constexpr tipc::ServiceObjectBase *GetObject() const { + return m_object; + } + }; + +} + diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp index a0b8f99..165a87e 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_object_manager.hpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include namespace ams::tipc { @@ -28,14 +28,14 @@ class ObjectManagerBase { protected: struct Entry { - util::TypedStorage object; - os::WaitableHolderType waitable_holder; + util::TypedStorage object; + os::MultiWaitHolderType multi_wait_holder; }; private: os::SdkMutex m_mutex{}; Entry *m_entries_start{}; Entry *m_entries_end{}; - os::WaitableManagerType *m_waitable_manager{}; + os::MultiWaitType *m_multi_wait{}; private: Entry *FindEntry(svc::Handle handle) { for (Entry *cur = m_entries_start; cur != m_entries_end; ++cur) { @@ -46,9 +46,9 @@ return nullptr; } - Entry *FindEntry(os::WaitableHolderType *holder) { + Entry *FindEntry(os::MultiWaitHolderType *holder) { for (Entry *cur = m_entries_start; cur != m_entries_end; ++cur) { - if (std::addressof(cur->waitable_holder) == holder) { + if (std::addressof(cur->multi_wait_holder) == holder) { return cur; } } @@ -57,9 +57,9 @@ public: constexpr ObjectManagerBase() = default; - void InitializeImpl(os::WaitableManagerType *manager, Entry *entries, size_t max_objects) { - /* Set our waitable manager. */ - m_waitable_manager = manager; + void InitializeImpl(os::MultiWaitType *multi_wait, Entry *entries, size_t max_objects) { + /* Set our multi wait. */ + m_multi_wait = multi_wait; /* Setup entry pointers. */ m_entries_start = entries; @@ -71,7 +71,7 @@ } } - void AddObject(WaitableObject &object) { + void AddObject(ObjectHolder &object) { /* Lock ourselves. */ std::scoped_lock lk(m_mutex); @@ -83,8 +83,8 @@ GetReference(entry->object) = object; /* Setup the entry's holder. */ - os::InitializeWaitableHolder(std::addressof(entry->waitable_holder), object.GetHandle()); - os::LinkWaitableHolder(m_waitable_manager, std::addressof(entry->waitable_holder)); + os::InitializeMultiWaitHolder(std::addressof(entry->multi_wait_holder), object.GetHandle()); + os::LinkMultiWaitHolder(m_multi_wait, std::addressof(entry->multi_wait_holder)); } void CloseObject(svc::Handle handle) { @@ -96,21 +96,21 @@ AMS_ABORT_UNLESS(entry != nullptr); /* Finalize the entry's holder. */ - os::UnlinkWaitableHolder(std::addressof(entry->waitable_holder)); - os::FinalizeWaitableHolder(std::addressof(entry->waitable_holder)); + os::UnlinkMultiWaitHolder(std::addressof(entry->multi_wait_holder)); + os::FinalizeMultiWaitHolder(std::addressof(entry->multi_wait_holder)); /* Destroy the object. */ GetReference(entry->object).Destroy(); } - Result ReplyAndReceive(os::WaitableHolderType **out_holder, WaitableObject *out_object, svc::Handle reply_target, os::WaitableManagerType *manager) { + Result ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, svc::Handle reply_target, os::MultiWaitType *multi_wait) { /* Declare signaled holder for processing ahead of time. */ - os::WaitableHolderType *signaled_holder; + os::MultiWaitHolderType *signaled_holder; /* Reply and receive until we get a newly signaled target. */ - Result result = os::SdkReplyAndReceive(out_holder, reply_target, manager); + Result result = os::SdkReplyAndReceive(out_holder, reply_target, multi_wait); for (signaled_holder = *out_holder; signaled_holder == nullptr; signaled_holder = *out_holder) { - result = os::SdkReplyAndReceive(out_holder, svc::InvalidHandle, manager); + result = os::SdkReplyAndReceive(out_holder, svc::InvalidHandle, multi_wait); } /* Find the entry matching the signaled holder. */ @@ -140,7 +140,7 @@ return ResultSuccess(); } - Result ProcessRequest(WaitableObject &object) { + Result ProcessRequest(ObjectHolder &object) { /* Get the method id. */ const auto method_id = svc::ipc::MessageBuffer::MessageHeader(svc::ipc::MessageBuffer(svc::ipc::GetMessageBuffer())).GetTag(); @@ -176,8 +176,8 @@ public: constexpr ObjectManager() = default; - void Initialize(os::WaitableManagerType *manager) { - this->InitializeImpl(manager, m_entries_storage, MaxObjects); + void Initialize(os::MultiWaitType *multi_wait) { + this->InitializeImpl(multi_wait, m_entries_storage, MaxObjects); } }; diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp index 33df54d..3c2b17f 100644 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp +++ b/libraries/libstratosphere/include/stratosphere/tipc/tipc_server_manager.hpp @@ -36,7 +36,7 @@ class PortManagerInterface { public: - virtual Result ProcessRequest(WaitableObject &object) = 0; + virtual Result ProcessRequest(ObjectHolder &object) = 0; }; template @@ -97,18 +97,18 @@ s32 m_id; std::atomic m_num_sessions; s32 m_port_number; - os::WaitableManagerType m_waitable_manager; + os::MultiWaitType m_multi_wait; DeferralManagerType m_deferral_manager; os::MessageQueueType m_message_queue; - os::WaitableHolderType m_message_queue_holder; + os::MultiWaitHolderType m_message_queue_holder; uintptr_t m_message_queue_storage[MaxSessions]; ObjectManagerBase *m_object_manager; ServerManagerImpl *m_server_manager; public: - PortManagerBase() : m_id(), m_num_sessions(), m_port_number(), m_waitable_manager(), m_deferral_manager(), m_message_queue(), m_message_queue_holder(), m_message_queue_storage(), m_object_manager(), m_server_manager() { + PortManagerBase() : m_id(), m_num_sessions(), m_port_number(), m_multi_wait(), m_deferral_manager(), m_message_queue(), m_message_queue_holder(), m_message_queue_storage(), m_object_manager(), m_server_manager() { /* Setup our message queue. */ os::InitializeMessageQueue(std::addressof(m_message_queue), m_message_queue_storage, util::size(m_message_queue_storage)); - os::InitializeWaitableHolder(std::addressof(m_message_queue_holder), std::addressof(m_message_queue), os::MessageQueueWaitType::ForNotEmpty); + os::InitializeMultiWaitHolder(std::addressof(m_message_queue_holder), std::addressof(m_message_queue), os::MessageQueueWaitType::ForNotEmpty); } constexpr s32 GetPortIndex() const { @@ -133,9 +133,9 @@ /* Reset our session count. */ m_num_sessions = 0; - /* Initialize our waitable manager. */ - os::InitializeWaitableManager(std::addressof(m_waitable_manager)); - os::LinkWaitableHolder(std::addressof(m_waitable_manager), std::addressof(m_message_queue_holder)); + /* Initialize our multi wait. */ + os::InitializeMultiWait(std::addressof(m_multi_wait)); + os::LinkMultiWaitHolder(std::addressof(m_multi_wait), std::addressof(m_message_queue_holder)); /* Initialize our object manager. */ m_object_manager = manager; @@ -145,8 +145,8 @@ /* Set our port number. */ this->m_port_number = index; - /* Create a waitable object for the port. */ - tipc::WaitableObject object; + /* Create an object holder for the port. */ + tipc::ObjectHolder object; /* Setup the object. */ object.InitializeAsPort(port_handle); @@ -155,7 +155,7 @@ m_object_manager->AddObject(object); } - virtual Result ProcessRequest(WaitableObject &object) override { + virtual Result ProcessRequest(ObjectHolder &object) override { /* Process the request, this must succeed because we succeeded when deferring earlier. */ R_ABORT_UNLESS(m_object_manager->ProcessRequest(object)); @@ -168,13 +168,13 @@ return m_object_manager->Reply(object.GetHandle()); } - Result ReplyAndReceive(os::WaitableHolderType **out_holder, WaitableObject *out_object, svc::Handle reply_target) { - return m_object_manager->ReplyAndReceive(out_holder, out_object, reply_target, std::addressof(m_waitable_manager)); + Result ReplyAndReceive(os::MultiWaitHolderType **out_holder, ObjectHolder *out_object, svc::Handle reply_target) { + return m_object_manager->ReplyAndReceive(out_holder, out_object, reply_target, std::addressof(m_multi_wait)); } void AddSession(svc::Handle session_handle, tipc::ServiceObjectBase *service_object) { - /* Create a waitable object for the session. */ - tipc::WaitableObject object; + /* Create an object holder for the session. */ + tipc::ObjectHolder object; /* Setup the object. */ object.InitializeAsSession(session_handle, true, service_object); @@ -219,7 +219,7 @@ } } - void CloseSession(WaitableObject &object) { + void CloseSession(ObjectHolder &object) { /* Get the object's handle. */ const auto handle = object.GetHandle(); @@ -233,7 +233,7 @@ --m_num_sessions; } - void CloseSessionIfNecessary(WaitableObject &object, bool necessary) { + void CloseSessionIfNecessary(ObjectHolder &object, bool necessary) { if (necessary) { /* Get the object's handle. */ const auto handle = object.GetHandle(); @@ -261,7 +261,7 @@ } } - void ProcessRegisterRetry(WaitableObject &object) { + void ProcessRegisterRetry(ObjectHolder &object) { if constexpr (IsDeferralSupported) { /* Acquire exclusive server manager access. */ std::scoped_lock lk(m_server_manager->GetMutex()); @@ -342,7 +342,7 @@ this->InitializeBase(id, sm, std::addressof(m_object_manager_impl)); /* Initialize our object manager. */ - m_object_manager_impl.Initialize(std::addressof(this->m_waitable_manager)); + m_object_manager_impl.Initialize(std::addressof(this->m_multi_wait)); } }; @@ -517,8 +517,8 @@ svc::Handle reply_target = svc::InvalidHandle; while (true) { /* Reply to our pending request, and receive a new one. */ - os::WaitableHolderType *signaled_holder = nullptr; - tipc::WaitableObject signaled_object{}; + os::MultiWaitHolderType *signaled_holder = nullptr; + tipc::ObjectHolder signaled_object{}; R_TRY_CATCH(port_manager.ReplyAndReceive(std::addressof(signaled_holder), std::addressof(signaled_object), reply_target)) { R_CATCH(os::ResultSessionClosedForReceive, os::ResultReceiveListBroken) { /* Close the object and continue. */ @@ -533,7 +533,7 @@ if (signaled_holder == nullptr) { /* A session was signaled, accessible via signaled_object. */ switch (signaled_object.GetType()) { - case WaitableObject::ObjectType_Port: + case ObjectHolder::ObjectType_Port: { /* Try to accept a new session */ svc::Handle session_handle; @@ -545,7 +545,7 @@ reply_target = svc::InvalidHandle; } break; - case WaitableObject::ObjectType_Session: + case ObjectHolder::ObjectType_Session: { /* Process the request */ const Result process_result = port_manager.GetObjectManager()->ProcessRequest(signaled_object); diff --git a/libraries/libstratosphere/include/stratosphere/tipc/tipc_waitable_object.hpp b/libraries/libstratosphere/include/stratosphere/tipc/tipc_waitable_object.hpp deleted file mode 100644 index cddce48..0000000 --- a/libraries/libstratosphere/include/stratosphere/tipc/tipc_waitable_object.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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 -#include -#include - -namespace ams::tipc { - - class WaitableObject { - public: - enum ObjectType : u8 { - ObjectType_Invalid = 0, - ObjectType_Port = 1, - ObjectType_Session = 2, - }; - private: - svc::Handle m_handle; - ObjectType m_type; - bool m_managed; - tipc::ServiceObjectBase *m_object; - private: - void InitializeImpl(ObjectType type, svc::Handle handle, bool managed, tipc::ServiceObjectBase *object) { - /* Validate that the object isn't already constructed. */ - AMS_ASSERT(m_type == ObjectType_Invalid); - - /* Set all fields. */ - m_handle = handle; - m_type = type; - m_managed = managed; - m_object = object; - } - public: - constexpr inline WaitableObject() : m_handle(svc::InvalidHandle), m_type(ObjectType_Invalid), m_managed(false), m_object(nullptr) { /* ... */ } - - void InitializeAsPort(svc::Handle handle) { - /* NOTE: Nintendo sets ports as managed, but this will cause a nullptr-deref if one is ever closed. */ - /* This is theoretically a non-issue, as ports can't be closed, but we will set ours as unmanaged, */ - /* just in case. */ - this->InitializeImpl(ObjectType_Port, handle, false, nullptr); - } - - void InitializeAsSession(svc::Handle handle, bool managed, tipc::ServiceObjectBase *object) { - this->InitializeImpl(ObjectType_Session, handle, managed, object); - } - - void Destroy() { - /* Validate that the object is constructed. */ - AMS_ASSERT(m_type != ObjectType_Invalid); - - /* If we're managed, destroy the associated object. */ - if (m_managed) { - if (auto * const deleter = m_object->GetDeleter(); deleter != nullptr) { - deleter->DeleteServiceObject(m_object); - } - } - - /* Reset all fields. */ - m_handle = svc::InvalidHandle; - m_type = ObjectType_Invalid; - m_managed = false; - m_object = nullptr; - } - - constexpr svc::Handle GetHandle() const { - return m_handle; - } - - constexpr ObjectType GetType() const { - return m_type; - } - - constexpr tipc::ServiceObjectBase *GetObject() const { - return m_object; - } - }; - -} - diff --git a/libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp b/libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp index 490d26f..acc91c2 100644 --- a/libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp +++ b/libraries/libstratosphere/source/ddsf/ddsf_event_handler.cpp @@ -42,10 +42,10 @@ return; } - /* Initialize waitable manager/holder. */ - os::InitializeWaitableManager(std::addressof(this->waitable_manager)); - os::InitializeWaitableHolder(std::addressof(this->loop_control_event_holder), this->loop_control_event.GetBase()); - os::LinkWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->loop_control_event_holder)); + /* Initialize multi wait/holder. */ + os::InitializeMultiWait(std::addressof(this->multi_wait)); + os::InitializeMultiWaitHolder(std::addressof(this->loop_control_event_holder), this->loop_control_event.GetBase()); + os::LinkMultiWaitHolder(std::addressof(this->multi_wait), std::addressof(this->loop_control_event_holder)); this->is_initialized = true; } @@ -58,10 +58,10 @@ return; } - /* Finalize waitable manager/holder. */ - os::UnlinkWaitableHolder(std::addressof(this->loop_control_event_holder)); - os::FinalizeWaitableHolder(std::addressof(this->loop_control_event_holder)); - os::FinalizeWaitableManager(std::addressof(this->waitable_manager)); + /* Finalize multi wait/holder. */ + os::UnlinkMultiWaitHolder(std::addressof(this->loop_control_event_holder)); + os::FinalizeMultiWaitHolder(std::addressof(this->loop_control_event_holder)); + os::FinalizeMultiWait(std::addressof(this->multi_wait)); this->is_initialized = false; } @@ -94,7 +94,7 @@ /* Process the command. */ switch (params->command) { case LoopControlCommand::Register: - params->target->Link(std::addressof(this->waitable_manager)); + params->target->Link(std::addressof(this->multi_wait)); break; case LoopControlCommand::Unregister: params->target->Unlink(); @@ -180,7 +180,7 @@ bool should_terminate = false; while (!should_terminate) { /* Wait for a holder to be signaled. */ - os::WaitableHolderType *event_holder = os::WaitAny(std::addressof(this->waitable_manager)); + os::MultiWaitHolderType *event_holder = os::WaitAny(std::addressof(this->multi_wait)); AMS_ASSERT(event_holder != nullptr); /* Check if we have a request to handle. */ diff --git a/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp b/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp index 1eec3c3..6ca76e4 100644 --- a/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp +++ b/libraries/libstratosphere/source/erpt/srv/erpt_srv_service.cpp @@ -97,13 +97,13 @@ psc::PmModule pm_module; psc::PmState pm_state; psc::PmFlagSet pm_flags; - os::WaitableHolderType module_event_holder; + os::MultiWaitHolderType module_event_holder; R_ABORT_UNLESS(pm_module.Initialize(psc::PmModuleId_Erpt, dependencies, util::size(dependencies), os::EventClearMode_ManualClear)); - os::InitializeWaitableHolder(std::addressof(module_event_holder), pm_module.GetEventPointer()->GetBase()); - os::SetWaitableHolderUserData(std::addressof(module_event_holder), static_cast(psc::PmModuleId_Erpt)); - this->AddUserWaitableHolder(std::addressof(module_event_holder)); + os::InitializeMultiWaitHolder(std::addressof(module_event_holder), pm_module.GetEventPointer()->GetBase()); + os::SetMultiWaitHolderUserData(std::addressof(module_event_holder), static_cast(psc::PmModuleId_Erpt)); + this->AddUserMultiWaitHolder(std::addressof(module_event_holder)); while (true) { /* NOTE: Nintendo checks the user holder data to determine what's signaled, we will prefer to just check the address. */ @@ -131,7 +131,7 @@ } else { AMS_ASSERT(false); } - this->AddUserWaitableHolder(signaled_holder); + this->AddUserMultiWaitHolder(signaled_holder); } } } diff --git a/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp b/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp index ab76975..a9f8ed8 100644 --- a/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp +++ b/libraries/libstratosphere/source/htclow/driver/htclow_usb_impl.cpp @@ -276,22 +276,22 @@ /* Get the state change event. */ os::SystemEventType *state_change_event = g_ds_client.GetStateChangeEvent(); - /* Setup waitable manager. */ - os::WaitableManagerType manager; - os::InitializeWaitableManager(std::addressof(manager)); + /* Setup multi wait. */ + os::MultiWaitType multi_wait; + os::InitializeMultiWait(std::addressof(multi_wait)); - /* Link waitable holders. */ - os::WaitableHolderType state_change_holder; - os::WaitableHolderType break_holder; - os::InitializeWaitableHolder(std::addressof(state_change_holder), state_change_event); - os::LinkWaitableHolder(std::addressof(manager), std::addressof(state_change_holder)); - os::InitializeWaitableHolder(std::addressof(break_holder), g_usb_break_event.GetBase()); - os::LinkWaitableHolder(std::addressof(manager), std::addressof(break_holder)); + /* Link multi wait holders. */ + os::MultiWaitHolderType state_change_holder; + os::MultiWaitHolderType break_holder; + os::InitializeMultiWaitHolder(std::addressof(state_change_holder), state_change_event); + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(state_change_holder)); + os::InitializeMultiWaitHolder(std::addressof(break_holder), g_usb_break_event.GetBase()); + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(break_holder)); /* Loop forever. */ while (true) { /* If we should break, do so. */ - if (os::WaitAny(std::addressof(manager)) == std::addressof(break_holder)) { + if (os::WaitAny(std::addressof(multi_wait)) == std::addressof(break_holder)) { break; } @@ -320,12 +320,12 @@ g_usb_break_event.Clear(); /* Unlink all holders. */ - os::UnlinkAllWaitableHolder(std::addressof(manager)); + os::UnlinkAllMultiWaitHolder(std::addressof(multi_wait)); - /* Finalize the waitable holders and manager. */ - os::FinalizeWaitableHolder(std::addressof(break_holder)); - os::FinalizeWaitableHolder(std::addressof(state_change_holder)); - os::FinalizeWaitableManager(std::addressof(manager)); + /* Finalize the multi wait/holders. */ + os::FinalizeMultiWaitHolder(std::addressof(break_holder)); + os::FinalizeMultiWaitHolder(std::addressof(state_change_holder)); + os::FinalizeMultiWait(std::addressof(multi_wait)); } } diff --git a/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp b/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp index 6a9a14c..e668577 100644 --- a/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp +++ b/libraries/libstratosphere/source/lm/srv/lm_ipc_server.cpp @@ -42,7 +42,7 @@ constinit util::TypedStorage g_pm_module_storage; constinit psc::PmModule *g_pm_module; - constinit os::WaitableHolderType g_pm_module_holder; + constinit os::MultiWaitHolderType g_pm_module_holder; constexpr const psc::PmModuleId PmModuleDependencies[] = { psc::PmModuleId_TmaHostIo, psc::PmModuleId_Fs }; @@ -67,15 +67,15 @@ g_pm_module = util::ConstructAt(g_pm_module_storage); R_ABORT_UNLESS(g_pm_module->Initialize(psc::PmModuleId_Lm, PmModuleDependencies, util::size(PmModuleDependencies), os::EventClearMode_ManualClear)); - /* Create the psc module waitable holder. */ - os::InitializeWaitableHolder(std::addressof(g_pm_module_holder), g_pm_module->GetEventPointer()->GetBase()); - os::SetWaitableHolderUserData(std::addressof(g_pm_module_holder), psc::PmModuleId_Lm); + /* Create the psc module multi wait holder. */ + os::InitializeMultiWaitHolder(std::addressof(g_pm_module_holder), g_pm_module->GetEventPointer()->GetBase()); + os::SetMultiWaitHolderUserData(std::addressof(g_pm_module_holder), psc::PmModuleId_Lm); /* Create the server manager. */ g_server_manager = util::ConstructAt(g_server_manager_storage); /* Add the pm module holder. */ - g_server_manager->AddUserWaitableHolder(std::addressof(g_pm_module_holder)); + g_server_manager->AddUserMultiWaitHolder(std::addressof(g_pm_module_holder)); /* Create services. */ R_ABORT_UNLESS(g_server_manager->RegisterObjectForServer(g_log_service_object.GetShared(), LogServiceName, LogSessionCountMax)); @@ -100,7 +100,7 @@ } else { /* If pm module, clear the event. */ g_pm_module->GetEventPointer()->Clear(); - g_server_manager->AddUserWaitableHolder(signaled_holder); + g_server_manager->AddUserMultiWaitHolder(signaled_holder); /* Get the power state. */ psc::PmState pm_state; diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event.cpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event.cpp index 2de8a5a..c15754a 100644 --- a/libraries/libstratosphere/source/os/impl/os_inter_process_event.cpp +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event.cpp @@ -16,7 +16,7 @@ #include #include "os_inter_process_event.hpp" #include "os_inter_process_event_impl.hpp" -#include "os_waitable_object_list.hpp" +#include "os_multiple_wait_object_list.hpp" namespace ams::os::impl { @@ -33,7 +33,7 @@ event->auto_clear = (clear_mode == EventClearMode_AutoClear); /* Create the waitlist node. */ - util::ConstructAt(event->waitable_object_list_storage); + util::ConstructAt(event->multi_wait_object_list_storage); /* Set state. */ event->state = InterProcessEventType::State_Initialized; @@ -71,7 +71,7 @@ } /* Destroy the waitlist. */ - util::DestroyAt(event->waitable_object_list_storage); + util::DestroyAt(event->multi_wait_object_list_storage); } void AttachInterProcessEvent(InterProcessEventType *event, Handle read_handle, bool read_handle_managed, Handle write_handle, bool write_handle_managed, EventClearMode clear_mode) { diff --git a/libraries/libstratosphere/source/os/impl/os_inter_process_event.hpp b/libraries/libstratosphere/source/os/impl/os_inter_process_event.hpp index 0b5ee90..aeca0fb 100644 --- a/libraries/libstratosphere/source/os/impl/os_inter_process_event.hpp +++ b/libraries/libstratosphere/source/os/impl/os_inter_process_event.hpp @@ -36,6 +36,6 @@ Handle GetReadableHandleOfInterProcessEvent(const InterProcessEventType *event); Handle GetWritableHandleOfInterProcessEvent(const InterProcessEventType *event); - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, InterProcessEventType *event); + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterProcessEventType *event); } diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_base.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_base.hpp new file mode 100644 index 0000000..b9761e7 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_base.hpp @@ -0,0 +1,77 @@ +/* + * 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::os::impl { + + class MultiWaitObjectList; + class MultiWaitImpl; + + class MultiWaitHolderBase { + private: + MultiWaitImpl *multi_wait = nullptr; + public: + util::IntrusiveListNode multi_wait_node; + util::IntrusiveListNode object_list_node; + public: + /* Gets whether the held object is currently signaled. */ + virtual TriBool IsSignaled() const = 0; + /* Adds to multi wait's object list, returns is signaled. */ + virtual TriBool LinkToObjectList() = 0; + /* Removes from the multi wait's object list. */ + virtual void UnlinkFromObjectList() = 0; + /* Gets handle to output, returns INVALID_HANDLE on failure. */ + virtual Handle GetHandle() const = 0; + /* Gets the amount of time remaining until this wakes up. */ + virtual TimeSpan GetAbsoluteWakeupTime() const { + return TimeSpan::FromNanoSeconds(std::numeric_limits::max()); + } + + /* Interface with multi wait. */ + void SetMultiWait(MultiWaitImpl *m) { + this->multi_wait = m; + } + + MultiWaitImpl *GetMultiWait() const { + return this->multi_wait; + } + + bool IsLinked() const { + return this->multi_wait != nullptr; + } + }; + + class MultiWaitHolderOfUserObject : public MultiWaitHolderBase { + public: + /* All user objects have no handle to wait on. */ + virtual Handle GetHandle() const override final { + return svc::InvalidHandle; + } + }; + + class MultiWaitHolderOfKernelObject : public MultiWaitHolderBase { + public: + /* All kernel objects have native handles, and thus don't have object list semantics. */ + virtual TriBool LinkToObjectList() override final { + return TriBool::Undefined; + } + virtual void UnlinkFromObjectList() override final { + /* ... */ + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_impl.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_impl.hpp new file mode 100644 index 0000000..844909d --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_impl.hpp @@ -0,0 +1,59 @@ +/* + * 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 "os_multiple_wait_holder_of_handle.hpp" +#include "os_multiple_wait_holder_of_event.hpp" +#include "os_multiple_wait_holder_of_inter_process_event.hpp" +#include "os_multiple_wait_holder_of_interrupt_event.hpp" +#include "os_multiple_wait_holder_of_timer_event.hpp" +#include "os_multiple_wait_holder_of_thread.hpp" +#include "os_multiple_wait_holder_of_semaphore.hpp" +#include "os_multiple_wait_holder_of_message_queue.hpp" + +namespace ams::os::impl { + + struct MultiWaitHolderImpl { + union { + util::TypedStorage holder_of_handle_storage; + util::TypedStorage holder_of_event_storage; + util::TypedStorage holder_of_inter_process_event_storage; + util::TypedStorage holder_of_interrupt_event_storage; + util::TypedStorage holder_of_timer_event_storage; + util::TypedStorage holder_of_thread_storage; + util::TypedStorage holder_of_semaphore_storage; + util::TypedStorage holder_of_mq_for_not_full_storage; + util::TypedStorage holder_of_mq_for_not_empty_storage; + }; + }; + + #define CHECK_HOLDER(T) \ + static_assert(std::is_base_of<::ams::os::impl::MultiWaitHolderBase, T>::value && std::is_trivially_destructible::value, #T) + + CHECK_HOLDER(MultiWaitHolderOfHandle); + CHECK_HOLDER(MultiWaitHolderOfEvent); + CHECK_HOLDER(MultiWaitHolderOfInterProcessEvent); + CHECK_HOLDER(MultiWaitHolderOfInterruptEvent); + CHECK_HOLDER(MultiWaitHolderOfTimerEvent); + CHECK_HOLDER(MultiWaitHolderOfThread); + CHECK_HOLDER(MultiWaitHolderOfSemaphore); + CHECK_HOLDER(MultiWaitHolderOfMessageQueueForNotFull); + CHECK_HOLDER(MultiWaitHolderOfMessageQueueForNotEmpty); + + #undef CHECK_HOLDER + + static_assert(std::is_trivial::value && std::is_trivially_destructible::value); + static_assert(sizeof(MultiWaitHolderImpl) == sizeof(os::MultiWaitHolderType::impl_storage)); +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_event.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_event.hpp new file mode 100644 index 0000000..574db2e --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_event.hpp @@ -0,0 +1,52 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_object_list.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfEvent : public MultiWaitHolderOfUserObject { + private: + EventType *event; + private: + TriBool IsSignaledImpl() const { + return this->event->signaled ? TriBool::True : TriBool::False; + } + public: + explicit MultiWaitHolderOfEvent(EventType *e) : event(e) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(GetReference(this->event->cs_event)); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(GetReference(this->event->cs_event)); + + GetReference(this->event->multi_wait_object_list_storage).LinkMultiWaitHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(GetReference(this->event->cs_event)); + + GetReference(this->event->multi_wait_object_list_storage).UnlinkMultiWaitHolder(*this); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_handle.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_handle.hpp new file mode 100644 index 0000000..a9e49b3 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_handle.hpp @@ -0,0 +1,37 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfHandle : public MultiWaitHolderOfKernelObject { + private: + Handle handle; + public: + explicit MultiWaitHolderOfHandle(Handle h) : handle(h) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override { + return this->handle; + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_inter_process_event.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_inter_process_event.hpp new file mode 100644 index 0000000..b780e2b --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_inter_process_event.hpp @@ -0,0 +1,38 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" +#include "os_inter_process_event.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfInterProcessEvent : public MultiWaitHolderOfKernelObject { + private: + InterProcessEventType *event; + public: + explicit MultiWaitHolderOfInterProcessEvent(InterProcessEventType *e) : event(e) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override { + return this->event->readable_handle; + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.cpp new file mode 100644 index 0000000..5180ff3 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.cpp @@ -0,0 +1,26 @@ +/* + * 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 "os_multiple_wait_holder_of_interrupt_event.hpp" +#include "os_interrupt_event_impl.hpp" + +namespace ams::os::impl { + + Handle MultiWaitHolderOfInterruptEvent::GetHandle() const { + return GetReference(event->impl).GetHandle(); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.hpp new file mode 100644 index 0000000..628c9a3 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_interrupt_event.hpp @@ -0,0 +1,35 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfInterruptEvent : public MultiWaitHolderOfKernelObject { + private: + InterruptEventType *event; + public: + explicit MultiWaitHolderOfInterruptEvent(InterruptEventType *e) : event(e) { /* ... */ } + + /* IsSignaled, GetHandle both implemented. */ + virtual TriBool IsSignaled() const override { + return TriBool::Undefined; + } + + virtual Handle GetHandle() const override; + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_message_queue.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_message_queue.hpp new file mode 100644 index 0000000..2fb57ff --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_message_queue.hpp @@ -0,0 +1,75 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_object_list.hpp" + +namespace ams::os::impl { + + template + class MultiWaitHolderOfMessageQueue : public MultiWaitHolderOfUserObject { + static_assert(WaitType == MessageQueueWaitType::ForNotEmpty || WaitType == MessageQueueWaitType::ForNotFull); + private: + MessageQueueType *mq; + private: + constexpr inline TriBool IsSignaledImpl() const { + if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) { + /* ForNotEmpty. */ + return this->mq->count > 0 ? TriBool::True : TriBool::False; + } else if constexpr (WaitType == MessageQueueWaitType::ForNotFull) { + /* ForNotFull */ + return this->mq->count < this->mq->capacity ? TriBool::True : TriBool::False; + } else { + static_assert(WaitType != WaitType); + } + } + + constexpr inline MultiWaitObjectList &GetObjectList() const { + if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) { + return GetReference(this->mq->waitlist_not_empty); + } else if constexpr (WaitType == MessageQueueWaitType::ForNotFull) { + return GetReference(this->mq->waitlist_not_full); + } else { + static_assert(WaitType != WaitType); + } + } + public: + explicit MultiWaitHolderOfMessageQueue(MessageQueueType *mq) : mq(mq) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(GetReference(this->mq->cs_queue)); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(GetReference(this->mq->cs_queue)); + + this->GetObjectList().LinkMultiWaitHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(GetReference(this->mq->cs_queue)); + + this->GetObjectList().UnlinkMultiWaitHolder(*this); + } + }; + + using MultiWaitHolderOfMessageQueueForNotEmpty = MultiWaitHolderOfMessageQueue; + using MultiWaitHolderOfMessageQueueForNotFull = MultiWaitHolderOfMessageQueue; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_semaphore.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_semaphore.hpp new file mode 100644 index 0000000..b3e76f6 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_semaphore.hpp @@ -0,0 +1,52 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_object_list.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfSemaphore : public MultiWaitHolderOfUserObject { + private: + SemaphoreType *semaphore; + private: + TriBool IsSignaledImpl() const { + return this->semaphore->count > 0 ? TriBool::True : TriBool::False; + } + public: + explicit MultiWaitHolderOfSemaphore(SemaphoreType *s) : semaphore(s) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(GetReference(this->semaphore->cs_sema)); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(GetReference(this->semaphore->cs_sema)); + + GetReference(this->semaphore->waitlist).LinkMultiWaitHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(GetReference(this->semaphore->cs_sema)); + + GetReference(this->semaphore->waitlist).UnlinkMultiWaitHolder(*this); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_thread.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_thread.hpp new file mode 100644 index 0000000..f47ae26 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_thread.hpp @@ -0,0 +1,51 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfThread : public MultiWaitHolderOfUserObject { + private: + ThreadType *thread; + private: + TriBool IsSignaledImpl() const { + return this->thread->state == ThreadType::State_Terminated ? TriBool::True : TriBool::False; + } + public: + explicit MultiWaitHolderOfThread(ThreadType *t) : thread(t) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(GetReference(this->thread->cs_thread)); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(GetReference(this->thread->cs_thread)); + + GetReference(this->thread->waitlist).LinkMultiWaitHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(GetReference(this->thread->cs_thread)); + + GetReference(this->thread->waitlist).UnlinkMultiWaitHolder(*this); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_timer_event.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_timer_event.hpp new file mode 100644 index 0000000..5558a25 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_holder_of_timer_event.hpp @@ -0,0 +1,67 @@ +/* + * 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 +#include "os_timer_event_helper.hpp" +#include "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_object_list.hpp" + +namespace ams::os::impl { + + class MultiWaitHolderOfTimerEvent : public MultiWaitHolderOfUserObject { + private: + TimerEventType *event; + private: + TriBool IsSignaledImpl() const { + TimeSpan cur_time = this->GetMultiWait()->GetCurrentTime(); + UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(this->event, cur_time); + return this->event->signaled ? TriBool::True : TriBool::False; + } + public: + explicit MultiWaitHolderOfTimerEvent(TimerEventType *e) : event(e) { /* ... */ } + + /* IsSignaled, Link, Unlink implemented. */ + virtual TriBool IsSignaled() const override { + std::scoped_lock lk(GetReference(this->event->cs_timer_event)); + return this->IsSignaledImpl(); + } + + virtual TriBool LinkToObjectList() override { + std::scoped_lock lk(GetReference(this->event->cs_timer_event)); + + GetReference(this->event->multi_wait_object_list_storage).LinkMultiWaitHolder(*this); + return this->IsSignaledImpl(); + } + + virtual void UnlinkFromObjectList() override { + std::scoped_lock lk(GetReference(this->event->cs_timer_event)); + + GetReference(this->event->multi_wait_object_list_storage).UnlinkMultiWaitHolder(*this); + } + + /* Gets the amount of time remaining until this wakes up. */ + virtual TimeSpan GetAbsoluteWakeupTime() const override { + std::scoped_lock lk(GetReference(this->event->cs_timer_event)); + + if (this->event->timer_state == TimerEventType::TimerState_Stop) { + return TimeSpan::FromNanoSeconds(std::numeric_limits::max()); + } + + return GetReference(this->event->next_time_to_wakeup); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp new file mode 100644 index 0000000..bf08db2 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.cpp @@ -0,0 +1,203 @@ +/* + * 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 "os_multiple_wait_impl.hpp" +#include "os_multiple_wait_object_list.hpp" +#include "os_tick_manager.hpp" + +namespace ams::os::impl { + + Result MultiWaitImpl::WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target) { + /* Prepare for processing. */ + this->signaled_holder = nullptr; + this->target_impl.SetCurrentThreadHandleForCancelWait(); + MultiWaitHolderBase *holder = this->LinkHoldersToObjectList(); + + /* Check if we've been signaled. */ + { + std::scoped_lock lk(this->cs_wait); + if (this->signaled_holder != nullptr) { + holder = this->signaled_holder; + } + } + + /* Process object array. */ + Result wait_result = ResultSuccess(); + if (holder != nullptr) { + if (reply && reply_target != svc::InvalidHandle) { + s32 index; + wait_result = this->target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0)); + if (R_FAILED(wait_result)) { + holder = nullptr; + } + } + } else { + wait_result = this->WaitAnyHandleImpl(std::addressof(holder), infinite, timeout, reply, reply_target); + } + + /* Unlink holders from the current object list. */ + this->UnlinkHoldersFromObjectList(); + + this->target_impl.ClearCurrentThreadHandleForCancelWait(); + + /* Set output holder. */ + *out = holder; + + return wait_result; + } + + Result MultiWaitImpl::WaitAnyHandleImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target) { + Handle object_handles[MaximumHandleCount]; + MultiWaitHolderBase *objects[MaximumHandleCount]; + + const s32 count = this->BuildHandleArray(object_handles, objects, MaximumHandleCount); + const TimeSpan end_time = infinite ? TimeSpan::FromNanoSeconds(std::numeric_limits::max()) : GetCurrentTick().ToTimeSpan() + timeout; + + while (true) { + this->current_time = GetCurrentTick().ToTimeSpan(); + + TimeSpan min_timeout = 0; + MultiWaitHolderBase *min_timeout_object = this->RecalculateNextTimeout(&min_timeout, end_time); + + s32 index = WaitInvalid; + Result wait_result = ResultSuccess(); + if (reply) { + if (infinite && min_timeout_object == nullptr) { + wait_result = this->target_impl.ReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target); + } else { + wait_result = this->target_impl.TimedReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target, min_timeout); + } + } else if (infinite && min_timeout_object == nullptr) { + wait_result = this->target_impl.WaitAny(std::addressof(index), object_handles, MaximumHandleCount, count); + } else { + if (count == 0 && min_timeout == 0) { + index = WaitTimedOut; + } else { + wait_result = this->target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout); + AMS_ABORT_UNLESS(index != WaitInvalid); + } + } + + if (index == WaitInvalid) { + *out = nullptr; + return wait_result; + } + + switch (index) { + case WaitTimedOut: + if (min_timeout_object) { + this->current_time = GetCurrentTick().ToTimeSpan(); + if (min_timeout_object->IsSignaled() == TriBool::True) { + std::scoped_lock lk(this->cs_wait); + this->signaled_holder = min_timeout_object; + *out = min_timeout_object; + return wait_result; + } + } else { + *out = nullptr; + return wait_result; + } + break; + case WaitCancelled: + { + std::scoped_lock lk(this->cs_wait); + if (this->signaled_holder) { + *out = this->signaled_holder; + return wait_result; + } + } + break; + default: /* 0 - 0x3F, valid. */ + { + AMS_ASSERT(0 <= index && index < static_cast(MaximumHandleCount)); + + std::scoped_lock lk(this->cs_wait); + this->signaled_holder = objects[index]; + *out = objects[index]; + return wait_result; + } + break; + } + + reply_target = svc::InvalidHandle; + } + } + + s32 MultiWaitImpl::BuildHandleArray(Handle out_handles[], MultiWaitHolderBase *out_objects[], s32 num) { + s32 count = 0; + + for (MultiWaitHolderBase &holder_base : this->multi_wait_list) { + if (Handle handle = holder_base.GetHandle(); handle != svc::InvalidHandle) { + AMS_ASSERT(count < num); + + out_handles[count] = handle; + out_objects[count] = &holder_base; + count++; + } + } + + return count; + } + + MultiWaitHolderBase *MultiWaitImpl::LinkHoldersToObjectList() { + MultiWaitHolderBase *signaled_holder = nullptr; + + for (MultiWaitHolderBase &holder_base : this->multi_wait_list) { + TriBool is_signaled = holder_base.LinkToObjectList(); + + if (signaled_holder == nullptr && is_signaled == TriBool::True) { + signaled_holder = &holder_base; + } + } + + return signaled_holder; + } + + void MultiWaitImpl::UnlinkHoldersFromObjectList() { + for (MultiWaitHolderBase &holder_base : this->multi_wait_list) { + holder_base.UnlinkFromObjectList(); + } + } + + MultiWaitHolderBase *MultiWaitImpl::RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time) { + MultiWaitHolderBase *min_timeout_holder = nullptr; + TimeSpan min_time = end_time; + + for (MultiWaitHolderBase &holder_base : this->multi_wait_list) { + if (const TimeSpan cur_time = holder_base.GetAbsoluteWakeupTime(); cur_time < min_time) { + min_timeout_holder = &holder_base; + min_time = cur_time; + } + } + + if (min_time < this->current_time) { + *out_min_timeout = 0; + } else { + *out_min_timeout = min_time - this->current_time; + } + return min_timeout_holder; + } + + void MultiWaitImpl::SignalAndWakeupThread(MultiWaitHolderBase *holder_base) { + std::scoped_lock lk(this->cs_wait); + + if (this->signaled_holder == nullptr) { + this->signaled_holder = holder_base; + this->target_impl.CancelWait(); + } + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp new file mode 100644 index 0000000..523032f --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_impl.hpp @@ -0,0 +1,113 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" + +#if defined(ATMOSPHERE_OS_HORIZON) + #include "os_multiple_wait_target_impl.os.horizon.hpp" +#else + #error "Unknown OS for ams::os::MultiWaitTargetImpl" +#endif + +namespace ams::os::impl { + + class MultiWaitImpl { + public: + static constexpr size_t MaximumHandleCount = MultiWaitTargetImpl::MaximumHandleCount; + static constexpr s32 WaitInvalid = -3; + static constexpr s32 WaitCancelled = -2; + static constexpr s32 WaitTimedOut = -1; + using MultiWaitList = util::IntrusiveListMemberTraits<&MultiWaitHolderBase::multi_wait_node>::ListType; + private: + MultiWaitList multi_wait_list; + MultiWaitHolderBase *signaled_holder; + TimeSpan current_time; + InternalCriticalSection cs_wait; + MultiWaitTargetImpl target_impl; + private: + Result WaitAnyImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target); + Result WaitAnyHandleImpl(MultiWaitHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target); + s32 BuildHandleArray(Handle out_handles[], MultiWaitHolderBase *out_objects[], s32 num); + + MultiWaitHolderBase *LinkHoldersToObjectList(); + void UnlinkHoldersFromObjectList(); + + MultiWaitHolderBase *RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time); + + MultiWaitHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout) { + MultiWaitHolderBase *holder = nullptr; + + const Result wait_result = this->WaitAnyImpl(std::addressof(holder), infinite, timeout, false, svc::InvalidHandle); + R_ASSERT(wait_result); + AMS_UNUSED(wait_result); + + return holder; + } + public: + /* Wait. */ + MultiWaitHolderBase *WaitAny() { + return this->WaitAnyImpl(true, TimeSpan::FromNanoSeconds(std::numeric_limits::max())); + } + + MultiWaitHolderBase *TryWaitAny() { + return this->WaitAnyImpl(false, TimeSpan(0)); + } + + MultiWaitHolderBase *TimedWaitAny(TimeSpan ts) { + return this->WaitAnyImpl(false, ts); + } + + Result ReplyAndReceive(MultiWaitHolderBase **out, Handle reply_target) { + return this->WaitAnyImpl(out, true, TimeSpan::FromNanoSeconds(std::numeric_limits::max()), true, reply_target); + } + + /* List management. */ + bool IsEmpty() const { + return this->multi_wait_list.empty(); + } + + void LinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { + this->multi_wait_list.push_back(holder_base); + } + + void UnlinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { + this->multi_wait_list.erase(this->multi_wait_list.iterator_to(holder_base)); + } + + void UnlinkAll() { + while (!this->IsEmpty()) { + this->multi_wait_list.front().SetMultiWait(nullptr); + this->multi_wait_list.pop_front(); + } + } + + void MoveAllFrom(MultiWaitImpl &other) { + /* Set ourselves as multi wait for all of the other's holders. */ + for (auto &w : other.multi_wait_list) { + w.SetMultiWait(this); + } + this->multi_wait_list.splice(this->multi_wait_list.end(), other.multi_wait_list); + } + + /* Other. */ + TimeSpan GetCurrentTime() const { + return this->current_time; + } + + void SignalAndWakeupThread(MultiWaitHolderBase *holder_base); + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_object_list.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_object_list.hpp new file mode 100644 index 0000000..842e749 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_object_list.hpp @@ -0,0 +1,53 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_impl.hpp" + +namespace ams::os::impl { + + class MultiWaitObjectList { + public: + using ListType = util::IntrusiveListMemberTraits<&MultiWaitHolderBase::object_list_node>::ListType; + private: + ListType object_list; + public: + void SignalAllThreads() { + for (MultiWaitHolderBase &holder_base : this->object_list) { + holder_base.GetMultiWait()->SignalAndWakeupThread(&holder_base); + } + } + + void BroadcastAllThreads() { + for (MultiWaitHolderBase &holder_base : this->object_list) { + holder_base.GetMultiWait()->SignalAndWakeupThread(nullptr); + } + } + + bool IsEmpty() const { + return this->object_list.empty(); + } + + void LinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { + this->object_list.push_back(holder_base); + } + + void UnlinkMultiWaitHolder(MultiWaitHolderBase &holder_base) { + this->object_list.erase(this->object_list.iterator_to(holder_base)); + } + }; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.cpp new file mode 100644 index 0000000..6573ff6 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.cpp @@ -0,0 +1,71 @@ +/* + * 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 "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_impl.hpp" + +namespace ams::os::impl { + + Result MultiWaitHorizonImpl::WaitSynchronizationN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns) { + AMS_ASSERT(!(num == 0 && ns == 0)); + s32 index = MultiWaitImpl::WaitInvalid; + + R_TRY_CATCH(svc::WaitSynchronization(std::addressof(index), static_cast(arr), num, ns)) { + R_CATCH(svc::ResultTimedOut) { index = MultiWaitImpl::WaitTimedOut; } + R_CATCH(svc::ResultCancelled) { index = MultiWaitImpl::WaitCancelled; } + /* All other results are critical errors. */ + /* svc::ResultThreadTerminating */ + /* svc::ResultInvalidHandle. */ + /* svc::ResultInvalidPointer */ + /* svc::ResultOutOfRange */ + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + *out_index = index; + return ResultSuccess(); + } + + Result MultiWaitHorizonImpl::ReplyAndReceiveN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns, Handle reply_target) { + /* NOTE: Nintendo does not initialize this value, which seems like it can cause incorrect behavior. */ + s32 index = MultiWaitImpl::WaitInvalid; + static_assert(MultiWaitImpl::WaitInvalid != -1); + + R_TRY_CATCH(svc::ReplyAndReceive(std::addressof(index), arr, num, reply_target, ns)) { + R_CATCH(svc::ResultTimedOut) { *out_index = MultiWaitImpl::WaitTimedOut; return R_CURRENT_RESULT; } + R_CATCH(svc::ResultCancelled) { *out_index = MultiWaitImpl::WaitCancelled; return R_CURRENT_RESULT; } + R_CATCH(svc::ResultSessionClosed) { + if (index == -1) { + *out_index = MultiWaitImpl::WaitInvalid; + return os::ResultSessionClosedForReply(); + } else { + *out_index = index; + return os::ResultSessionClosedForReceive(); + } + } + R_CATCH(svc::ResultReceiveListBroken) { + *out_index = index; + return os::ResultReceiveListBroken(); + } + } R_END_TRY_CATCH_WITH_ABORT_UNLESS; + + *out_index = index; + return ResultSuccess(); + } + + void MultiWaitHorizonImpl::CancelWait() { + R_ABORT_UNLESS(svc::CancelSynchronization(this->handle)); + } + +} diff --git a/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.hpp new file mode 100644 index 0000000..ad023af --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_multiple_wait_target_impl.os.horizon.hpp @@ -0,0 +1,68 @@ +/* + * 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 +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + class MultiWaitHorizonImpl { + public: + static constexpr size_t MaximumHandleCount = static_cast(ams::svc::ArgumentHandleCountMax); + private: + Handle handle; + private: + Result WaitSynchronizationN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns); + Result ReplyAndReceiveN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns, Handle reply_target); + public: + void CancelWait(); + + Result WaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num) { + return this->WaitSynchronizationN(out_index, num, arr, array_size, svc::WaitInfinite); + } + + Result TryWaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num) { + return this->WaitSynchronizationN(out_index, num, arr, array_size, 0); + } + + Result TimedWaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num, TimeSpan ts) { + s64 timeout = ts.GetNanoSeconds(); + if (timeout < 0) { + timeout = 0; + } + return this->WaitSynchronizationN(out_index, num, arr, array_size, timeout); + } + + Result ReplyAndReceive(s32 *out_index, Handle arr[], s32 array_size, s32 num, Handle reply_target) { + return this->ReplyAndReceiveN(out_index, num, arr, array_size, std::numeric_limits::max(), reply_target); + } + + Result TimedReplyAndReceive(s32 *out_index, Handle arr[], s32 array_size, s32 num, Handle reply_target, TimeSpan ts) { + return this->ReplyAndReceiveN(out_index, num, arr, array_size, ts.GetNanoSeconds(), reply_target); + } + + void SetCurrentThreadHandleForCancelWait() { + this->handle = GetCurrentThreadHandle(); + } + + void ClearCurrentThreadHandleForCancelWait() { + this->handle = svc::InvalidHandle; + } + }; + + using MultiWaitTargetImpl = MultiWaitHorizonImpl; + +} diff --git a/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp b/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp index e6c456a..a4e593e 100644 --- a/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp +++ b/libraries/libstratosphere/source/os/impl/os_thread_manager.cpp @@ -15,10 +15,10 @@ */ #include #include "os_thread_manager.hpp" -#include "os_waitable_manager_impl.hpp" -#include "os_waitable_holder_base.hpp" -#include "os_waitable_holder_impl.hpp" -#include "os_waitable_object_list.hpp" +#include "os_multiple_wait_impl.hpp" +#include "os_multiple_wait_holder_base.hpp" +#include "os_multiple_wait_holder_impl.hpp" +#include "os_multiple_wait_object_list.hpp" #include "os_utility.hpp" namespace ams::os::impl { diff --git a/libraries/libstratosphere/source/os/impl/os_utility.hpp b/libraries/libstratosphere/source/os/impl/os_utility.hpp index bbbd9ae..17c66b0 100644 --- a/libraries/libstratosphere/source/os/impl/os_utility.hpp +++ b/libraries/libstratosphere/source/os/impl/os_utility.hpp @@ -14,8 +14,6 @@ * along with this program. If not, see . */ #pragma once -#include "os_waitable_holder_base.hpp" -#include "os_waitable_manager_impl.hpp" namespace ams::os::impl { diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_base.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_base.hpp deleted file mode 100644 index c6c098f..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_base.hpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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::os::impl { - - class WaitableObjectList; - class WaitableManagerImpl; - - class WaitableHolderBase { - private: - WaitableManagerImpl *manager = nullptr; - public: - util::IntrusiveListNode manager_node; - util::IntrusiveListNode object_list_node; - public: - /* Gets whether the held waitable is currently signaled. */ - virtual TriBool IsSignaled() const = 0; - /* Adds to manager's object list, returns is signaled. */ - virtual TriBool LinkToObjectList() = 0; - /* Removes from the manager's object list. */ - virtual void UnlinkFromObjectList() = 0; - /* Gets handle to output, returns INVALID_HANDLE on failure. */ - virtual Handle GetHandle() const = 0; - /* Gets the amount of time remaining until this wakes up. */ - virtual TimeSpan GetAbsoluteWakeupTime() const { - return TimeSpan::FromNanoSeconds(std::numeric_limits::max()); - } - - /* Interface with manager. */ - void SetManager(WaitableManagerImpl *m) { - this->manager = m; - } - - WaitableManagerImpl *GetManager() const { - return this->manager; - } - - bool IsLinkedToManager() const { - return this->manager != nullptr; - } - }; - - class WaitableHolderOfUserObject : public WaitableHolderBase { - public: - /* All user objects have no handle to wait on. */ - virtual Handle GetHandle() const override final { - return svc::InvalidHandle; - } - }; - - class WaitableHolderOfKernelObject : public WaitableHolderBase { - public: - /* All kernel objects have native handles, and thus don't have object list semantics. */ - virtual TriBool LinkToObjectList() override final { - return TriBool::Undefined; - } - virtual void UnlinkFromObjectList() override final { - /* ... */ - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp deleted file mode 100644 index c479830..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_impl.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 "os_waitable_holder_of_handle.hpp" -#include "os_waitable_holder_of_event.hpp" -#include "os_waitable_holder_of_inter_process_event.hpp" -#include "os_waitable_holder_of_interrupt_event.hpp" -#include "os_waitable_holder_of_timer_event.hpp" -#include "os_waitable_holder_of_thread.hpp" -#include "os_waitable_holder_of_semaphore.hpp" -#include "os_waitable_holder_of_message_queue.hpp" - -namespace ams::os::impl { - - struct WaitableHolderImpl { - union { - util::TypedStorage holder_of_handle_storage; - util::TypedStorage holder_of_event_storage; - util::TypedStorage holder_of_inter_process_event_storage; - util::TypedStorage holder_of_interrupt_event_storage; - util::TypedStorage holder_of_timer_event_storage; - util::TypedStorage holder_of_thread_storage; - util::TypedStorage holder_of_semaphore_storage; - util::TypedStorage holder_of_mq_for_not_full_storage; - util::TypedStorage holder_of_mq_for_not_empty_storage; - }; - }; - - #define CHECK_HOLDER(T) \ - static_assert(std::is_base_of<::ams::os::impl::WaitableHolderBase, T>::value && std::is_trivially_destructible::value, #T) - - CHECK_HOLDER(WaitableHolderOfHandle); - CHECK_HOLDER(WaitableHolderOfEvent); - CHECK_HOLDER(WaitableHolderOfInterProcessEvent); - CHECK_HOLDER(WaitableHolderOfInterruptEvent); - CHECK_HOLDER(WaitableHolderOfTimerEvent); - CHECK_HOLDER(WaitableHolderOfThread); - CHECK_HOLDER(WaitableHolderOfSemaphore); - CHECK_HOLDER(WaitableHolderOfMessageQueueForNotFull); - CHECK_HOLDER(WaitableHolderOfMessageQueueForNotEmpty); - - #undef CHECK_HOLDER - - static_assert(std::is_trivial::value && std::is_trivially_destructible::value); - static_assert(sizeof(WaitableHolderImpl) == sizeof(os::WaitableHolderType::impl_storage)); -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp deleted file mode 100644 index 8b203c4..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_event.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" -#include "os_waitable_object_list.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfEvent : public WaitableHolderOfUserObject { - private: - EventType *event; - private: - TriBool IsSignaledImpl() const { - return this->event->signaled ? TriBool::True : TriBool::False; - } - public: - explicit WaitableHolderOfEvent(EventType *e) : event(e) { /* ... */ } - - /* IsSignaled, Link, Unlink implemented. */ - virtual TriBool IsSignaled() const override { - std::scoped_lock lk(GetReference(this->event->cs_event)); - return this->IsSignaledImpl(); - } - - virtual TriBool LinkToObjectList() override { - std::scoped_lock lk(GetReference(this->event->cs_event)); - - GetReference(this->event->waitable_object_list_storage).LinkWaitableHolder(*this); - return this->IsSignaledImpl(); - } - - virtual void UnlinkFromObjectList() override { - std::scoped_lock lk(GetReference(this->event->cs_event)); - - GetReference(this->event->waitable_object_list_storage).UnlinkWaitableHolder(*this); - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp deleted file mode 100644 index 5e08cac..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_handle.hpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfHandle : public WaitableHolderOfKernelObject { - private: - Handle handle; - public: - explicit WaitableHolderOfHandle(Handle h) : handle(h) { /* ... */ } - - /* IsSignaled, GetHandle both implemented. */ - virtual TriBool IsSignaled() const override { - return TriBool::Undefined; - } - - virtual Handle GetHandle() const override { - return this->handle; - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp deleted file mode 100644 index 3012da3..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_inter_process_event.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" -#include "os_inter_process_event.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfInterProcessEvent : public WaitableHolderOfKernelObject { - private: - InterProcessEventType *event; - public: - explicit WaitableHolderOfInterProcessEvent(InterProcessEventType *e) : event(e) { /* ... */ } - - /* IsSignaled, GetHandle both implemented. */ - virtual TriBool IsSignaled() const override { - return TriBool::Undefined; - } - - virtual Handle GetHandle() const override { - return this->event->readable_handle; - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.cpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.cpp deleted file mode 100644 index e553f13..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 "os_waitable_holder_of_interrupt_event.hpp" -#include "os_interrupt_event_impl.hpp" - -namespace ams::os::impl { - - Handle WaitableHolderOfInterruptEvent::GetHandle() const { - return GetReference(event->impl).GetHandle(); - } - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp deleted file mode 100644 index 10dcea9..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_interrupt_event.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfInterruptEvent : public WaitableHolderOfKernelObject { - private: - InterruptEventType *event; - public: - explicit WaitableHolderOfInterruptEvent(InterruptEventType *e) : event(e) { /* ... */ } - - /* IsSignaled, GetHandle both implemented. */ - virtual TriBool IsSignaled() const override { - return TriBool::Undefined; - } - - virtual Handle GetHandle() const override; - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp deleted file mode 100644 index bc54683..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_message_queue.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" -#include "os_waitable_object_list.hpp" - -namespace ams::os::impl { - - template - class WaitableHolderOfMessageQueue : public WaitableHolderOfUserObject { - static_assert(WaitType == MessageQueueWaitType::ForNotEmpty || WaitType == MessageQueueWaitType::ForNotFull); - private: - MessageQueueType *mq; - private: - constexpr inline TriBool IsSignaledImpl() const { - if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) { - /* ForNotEmpty. */ - return this->mq->count > 0 ? TriBool::True : TriBool::False; - } else if constexpr (WaitType == MessageQueueWaitType::ForNotFull) { - /* ForNotFull */ - return this->mq->count < this->mq->capacity ? TriBool::True : TriBool::False; - } else { - static_assert(WaitType != WaitType); - } - } - - constexpr inline WaitableObjectList &GetObjectList() const { - if constexpr (WaitType == MessageQueueWaitType::ForNotEmpty) { - return GetReference(this->mq->waitlist_not_empty); - } else if constexpr (WaitType == MessageQueueWaitType::ForNotFull) { - return GetReference(this->mq->waitlist_not_full); - } else { - static_assert(WaitType != WaitType); - } - } - public: - explicit WaitableHolderOfMessageQueue(MessageQueueType *mq) : mq(mq) { /* ... */ } - - /* IsSignaled, Link, Unlink implemented. */ - virtual TriBool IsSignaled() const override { - std::scoped_lock lk(GetReference(this->mq->cs_queue)); - return this->IsSignaledImpl(); - } - - virtual TriBool LinkToObjectList() override { - std::scoped_lock lk(GetReference(this->mq->cs_queue)); - - this->GetObjectList().LinkWaitableHolder(*this); - return this->IsSignaledImpl(); - } - - virtual void UnlinkFromObjectList() override { - std::scoped_lock lk(GetReference(this->mq->cs_queue)); - - this->GetObjectList().UnlinkWaitableHolder(*this); - } - }; - - using WaitableHolderOfMessageQueueForNotEmpty = WaitableHolderOfMessageQueue; - using WaitableHolderOfMessageQueueForNotFull = WaitableHolderOfMessageQueue; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_semaphore.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_semaphore.hpp deleted file mode 100644 index bc42b42..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_semaphore.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" -#include "os_waitable_object_list.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfSemaphore : public WaitableHolderOfUserObject { - private: - SemaphoreType *semaphore; - private: - TriBool IsSignaledImpl() const { - return this->semaphore->count > 0 ? TriBool::True : TriBool::False; - } - public: - explicit WaitableHolderOfSemaphore(SemaphoreType *s) : semaphore(s) { /* ... */ } - - /* IsSignaled, Link, Unlink implemented. */ - virtual TriBool IsSignaled() const override { - std::scoped_lock lk(GetReference(this->semaphore->cs_sema)); - return this->IsSignaledImpl(); - } - - virtual TriBool LinkToObjectList() override { - std::scoped_lock lk(GetReference(this->semaphore->cs_sema)); - - GetReference(this->semaphore->waitlist).LinkWaitableHolder(*this); - return this->IsSignaledImpl(); - } - - virtual void UnlinkFromObjectList() override { - std::scoped_lock lk(GetReference(this->semaphore->cs_sema)); - - GetReference(this->semaphore->waitlist).UnlinkWaitableHolder(*this); - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp deleted file mode 100644 index 19a10a8..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_thread.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfThread : public WaitableHolderOfUserObject { - private: - ThreadType *thread; - private: - TriBool IsSignaledImpl() const { - return this->thread->state == ThreadType::State_Terminated ? TriBool::True : TriBool::False; - } - public: - explicit WaitableHolderOfThread(ThreadType *t) : thread(t) { /* ... */ } - - /* IsSignaled, Link, Unlink implemented. */ - virtual TriBool IsSignaled() const override { - std::scoped_lock lk(GetReference(this->thread->cs_thread)); - return this->IsSignaledImpl(); - } - - virtual TriBool LinkToObjectList() override { - std::scoped_lock lk(GetReference(this->thread->cs_thread)); - - GetReference(this->thread->waitlist).LinkWaitableHolder(*this); - return this->IsSignaledImpl(); - } - - virtual void UnlinkFromObjectList() override { - std::scoped_lock lk(GetReference(this->thread->cs_thread)); - - GetReference(this->thread->waitlist).UnlinkWaitableHolder(*this); - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_timer_event.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_timer_event.hpp deleted file mode 100644 index 949df7b..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_holder_of_timer_event.hpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 -#include "os_timer_event_helper.hpp" -#include "os_waitable_holder_base.hpp" -#include "os_waitable_object_list.hpp" - -namespace ams::os::impl { - - class WaitableHolderOfTimerEvent : public WaitableHolderOfUserObject { - private: - TimerEventType *event; - private: - TriBool IsSignaledImpl() const { - TimeSpan cur_time = this->GetManager()->GetCurrentTime(); - UpdateSignalStateAndRecalculateNextTimeToWakeupUnsafe(this->event, cur_time); - return this->event->signaled ? TriBool::True : TriBool::False; - } - public: - explicit WaitableHolderOfTimerEvent(TimerEventType *e) : event(e) { /* ... */ } - - /* IsSignaled, Link, Unlink implemented. */ - virtual TriBool IsSignaled() const override { - std::scoped_lock lk(GetReference(this->event->cs_timer_event)); - return this->IsSignaledImpl(); - } - - virtual TriBool LinkToObjectList() override { - std::scoped_lock lk(GetReference(this->event->cs_timer_event)); - - GetReference(this->event->waitable_object_list_storage).LinkWaitableHolder(*this); - return this->IsSignaledImpl(); - } - - virtual void UnlinkFromObjectList() override { - std::scoped_lock lk(GetReference(this->event->cs_timer_event)); - - GetReference(this->event->waitable_object_list_storage).UnlinkWaitableHolder(*this); - } - - /* Gets the amount of time remaining until this wakes up. */ - virtual TimeSpan GetAbsoluteWakeupTime() const override { - std::scoped_lock lk(GetReference(this->event->cs_timer_event)); - - if (this->event->timer_state == TimerEventType::TimerState_Stop) { - return TimeSpan::FromNanoSeconds(std::numeric_limits::max()); - } - - return GetReference(this->event->next_time_to_wakeup); - } - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp b/libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp deleted file mode 100644 index 2595b83..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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 "os_waitable_manager_impl.hpp" -#include "os_waitable_object_list.hpp" -#include "os_tick_manager.hpp" - -namespace ams::os::impl { - - Result WaitableManagerImpl::WaitAnyImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target) { - /* Prepare for processing. */ - this->signaled_holder = nullptr; - this->target_impl.SetCurrentThreadHandleForCancelWait(); - WaitableHolderBase *holder = this->LinkHoldersToObjectList(); - - /* Check if we've been signaled. */ - { - std::scoped_lock lk(this->cs_wait); - if (this->signaled_holder != nullptr) { - holder = this->signaled_holder; - } - } - - /* Process object array. */ - Result wait_result = ResultSuccess(); - if (holder != nullptr) { - if (reply && reply_target != svc::InvalidHandle) { - s32 index; - wait_result = this->target_impl.TimedReplyAndReceive(std::addressof(index), nullptr, 0, 0, reply_target, TimeSpan::FromNanoSeconds(0)); - if (R_FAILED(wait_result)) { - holder = nullptr; - } - } - } else { - wait_result = this->WaitAnyHandleImpl(std::addressof(holder), infinite, timeout, reply, reply_target); - } - - /* Unlink holders from the current object list. */ - this->UnlinkHoldersFromObjectList(); - - this->target_impl.ClearCurrentThreadHandleForCancelWait(); - - /* Set output holder. */ - *out = holder; - - return wait_result; - } - - Result WaitableManagerImpl::WaitAnyHandleImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target) { - Handle object_handles[MaximumHandleCount]; - WaitableHolderBase *objects[MaximumHandleCount]; - - const s32 count = this->BuildHandleArray(object_handles, objects, MaximumHandleCount); - const TimeSpan end_time = infinite ? TimeSpan::FromNanoSeconds(std::numeric_limits::max()) : GetCurrentTick().ToTimeSpan() + timeout; - - while (true) { - this->current_time = GetCurrentTick().ToTimeSpan(); - - TimeSpan min_timeout = 0; - WaitableHolderBase *min_timeout_object = this->RecalculateNextTimeout(&min_timeout, end_time); - - s32 index = WaitInvalid; - Result wait_result = ResultSuccess(); - if (reply) { - if (infinite && min_timeout_object == nullptr) { - wait_result = this->target_impl.ReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target); - } else { - wait_result = this->target_impl.TimedReplyAndReceive(std::addressof(index), object_handles, MaximumHandleCount, count, reply_target, min_timeout); - } - } else if (infinite && min_timeout_object == nullptr) { - wait_result = this->target_impl.WaitAny(std::addressof(index), object_handles, MaximumHandleCount, count); - } else { - if (count == 0 && min_timeout == 0) { - index = WaitTimedOut; - } else { - wait_result = this->target_impl.TimedWaitAny(std::addressof(index), object_handles, MaximumHandleCount, count, min_timeout); - AMS_ABORT_UNLESS(index != WaitInvalid); - } - } - - if (index == WaitInvalid) { - *out = nullptr; - return wait_result; - } - - switch (index) { - case WaitTimedOut: - if (min_timeout_object) { - this->current_time = GetCurrentTick().ToTimeSpan(); - if (min_timeout_object->IsSignaled() == TriBool::True) { - std::scoped_lock lk(this->cs_wait); - this->signaled_holder = min_timeout_object; - *out = min_timeout_object; - return wait_result; - } - } else { - *out = nullptr; - return wait_result; - } - break; - case WaitCancelled: - { - std::scoped_lock lk(this->cs_wait); - if (this->signaled_holder) { - *out = this->signaled_holder; - return wait_result; - } - } - break; - default: /* 0 - 0x3F, valid. */ - { - AMS_ASSERT(0 <= index && index < static_cast(MaximumHandleCount)); - - std::scoped_lock lk(this->cs_wait); - this->signaled_holder = objects[index]; - *out = objects[index]; - return wait_result; - } - } - - reply_target = svc::InvalidHandle; - } - } - - s32 WaitableManagerImpl::BuildHandleArray(Handle out_handles[], WaitableHolderBase *out_objects[], s32 num) { - s32 count = 0; - - for (WaitableHolderBase &holder_base : this->waitable_list) { - if (Handle handle = holder_base.GetHandle(); handle != svc::InvalidHandle) { - AMS_ASSERT(count < num); - - out_handles[count] = handle; - out_objects[count] = &holder_base; - count++; - } - } - - return count; - } - - WaitableHolderBase *WaitableManagerImpl::LinkHoldersToObjectList() { - WaitableHolderBase *signaled_holder = nullptr; - - for (WaitableHolderBase &holder_base : this->waitable_list) { - TriBool is_signaled = holder_base.LinkToObjectList(); - - if (signaled_holder == nullptr && is_signaled == TriBool::True) { - signaled_holder = &holder_base; - } - } - - return signaled_holder; - } - - void WaitableManagerImpl::UnlinkHoldersFromObjectList() { - for (WaitableHolderBase &holder_base : this->waitable_list) { - holder_base.UnlinkFromObjectList(); - } - } - - WaitableHolderBase *WaitableManagerImpl::RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time) { - WaitableHolderBase *min_timeout_holder = nullptr; - TimeSpan min_time = end_time; - - for (WaitableHolderBase &holder_base : this->waitable_list) { - if (const TimeSpan cur_time = holder_base.GetAbsoluteWakeupTime(); cur_time < min_time) { - min_timeout_holder = &holder_base; - min_time = cur_time; - } - } - - if (min_time < this->current_time) { - *out_min_timeout = 0; - } else { - *out_min_timeout = min_time - this->current_time; - } - return min_timeout_holder; - } - - void WaitableManagerImpl::SignalAndWakeupThread(WaitableHolderBase *holder_base) { - std::scoped_lock lk(this->cs_wait); - - if (this->signaled_holder == nullptr) { - this->signaled_holder = holder_base; - this->target_impl.CancelWait(); - } - } - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp deleted file mode 100644 index 9ac6df9..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_manager_impl.hpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" - -#if defined(ATMOSPHERE_OS_HORIZON) - #include "os_waitable_manager_target_impl.os.horizon.hpp" -#else - #error "Unknown OS for ams::os::WaitableManagerTargetImpl" -#endif - -namespace ams::os::impl { - - class WaitableManagerImpl { - public: - static constexpr size_t MaximumHandleCount = WaitableManagerTargetImpl::MaximumHandleCount; - static constexpr s32 WaitInvalid = -3; - static constexpr s32 WaitCancelled = -2; - static constexpr s32 WaitTimedOut = -1; - using ListType = util::IntrusiveListMemberTraits<&WaitableHolderBase::manager_node>::ListType; - private: - ListType waitable_list; - WaitableHolderBase *signaled_holder; - TimeSpan current_time; - InternalCriticalSection cs_wait; - WaitableManagerTargetImpl target_impl; - private: - Result WaitAnyImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target); - Result WaitAnyHandleImpl(WaitableHolderBase **out, bool infinite, TimeSpan timeout, bool reply, Handle reply_target); - s32 BuildHandleArray(Handle out_handles[], WaitableHolderBase *out_objects[], s32 num); - - WaitableHolderBase *LinkHoldersToObjectList(); - void UnlinkHoldersFromObjectList(); - - WaitableHolderBase *RecalculateNextTimeout(TimeSpan *out_min_timeout, TimeSpan end_time); - - WaitableHolderBase *WaitAnyImpl(bool infinite, TimeSpan timeout) { - WaitableHolderBase *holder = nullptr; - - const Result wait_result = this->WaitAnyImpl(std::addressof(holder), infinite, timeout, false, svc::InvalidHandle); - R_ASSERT(wait_result); - AMS_UNUSED(wait_result); - - return holder; - } - public: - /* Wait. */ - WaitableHolderBase *WaitAny() { - return this->WaitAnyImpl(true, TimeSpan::FromNanoSeconds(std::numeric_limits::max())); - } - - WaitableHolderBase *TryWaitAny() { - return this->WaitAnyImpl(false, TimeSpan(0)); - } - - WaitableHolderBase *TimedWaitAny(TimeSpan ts) { - return this->WaitAnyImpl(false, ts); - } - - Result ReplyAndReceive(WaitableHolderBase **out, Handle reply_target) { - return this->WaitAnyImpl(out, true, TimeSpan::FromNanoSeconds(std::numeric_limits::max()), true, reply_target); - } - - /* List management. */ - bool IsEmpty() const { - return this->waitable_list.empty(); - } - - void LinkWaitableHolder(WaitableHolderBase &holder_base) { - this->waitable_list.push_back(holder_base); - } - - void UnlinkWaitableHolder(WaitableHolderBase &holder_base) { - this->waitable_list.erase(this->waitable_list.iterator_to(holder_base)); - } - - void UnlinkAll() { - while (!this->IsEmpty()) { - this->waitable_list.front().SetManager(nullptr); - this->waitable_list.pop_front(); - } - } - - void MoveAllFrom(WaitableManagerImpl &other) { - /* Set manager for all of the other's waitables. */ - for (auto &w : other.waitable_list) { - w.SetManager(this); - } - this->waitable_list.splice(this->waitable_list.end(), other.waitable_list); - } - - /* Other. */ - TimeSpan GetCurrentTime() const { - return this->current_time; - } - - void SignalAndWakeupThread(WaitableHolderBase *holder_base); - }; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_manager_target_impl.os.horizon.cpp b/libraries/libstratosphere/source/os/impl/os_waitable_manager_target_impl.os.horizon.cpp deleted file mode 100644 index e567cf4..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_manager_target_impl.os.horizon.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" -#include "os_waitable_manager_impl.hpp" - -namespace ams::os::impl { - - Result WaitableManagerHorizonImpl::WaitSynchronizationN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns) { - AMS_ASSERT(!(num == 0 && ns == 0)); - s32 index = WaitableManagerImpl::WaitInvalid; - - R_TRY_CATCH(svc::WaitSynchronization(std::addressof(index), static_cast(arr), num, ns)) { - R_CATCH(svc::ResultTimedOut) { index = WaitableManagerImpl::WaitTimedOut; } - R_CATCH(svc::ResultCancelled) { index = WaitableManagerImpl::WaitCancelled; } - /* All other results are critical errors. */ - /* svc::ResultThreadTerminating */ - /* svc::ResultInvalidHandle. */ - /* svc::ResultInvalidPointer */ - /* svc::ResultOutOfRange */ - } R_END_TRY_CATCH_WITH_ABORT_UNLESS; - - *out_index = index; - return ResultSuccess(); - } - - Result WaitableManagerHorizonImpl::ReplyAndReceiveN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns, Handle reply_target) { - /* NOTE: Nintendo does not initialize this value, which seems like it can cause incorrect behavior. */ - s32 index = WaitableManagerImpl::WaitInvalid; - static_assert(WaitableManagerImpl::WaitInvalid != -1); - - R_TRY_CATCH(svc::ReplyAndReceive(std::addressof(index), arr, num, reply_target, ns)) { - R_CATCH(svc::ResultTimedOut) { *out_index = WaitableManagerImpl::WaitTimedOut; return R_CURRENT_RESULT; } - R_CATCH(svc::ResultCancelled) { *out_index = WaitableManagerImpl::WaitCancelled; return R_CURRENT_RESULT; } - R_CATCH(svc::ResultSessionClosed) { - if (index == -1) { - *out_index = WaitableManagerImpl::WaitInvalid; - return os::ResultSessionClosedForReply(); - } else { - *out_index = index; - return os::ResultSessionClosedForReceive(); - } - } - R_CATCH(svc::ResultReceiveListBroken) { - *out_index = index; - return os::ResultReceiveListBroken(); - } - } R_END_TRY_CATCH_WITH_ABORT_UNLESS; - - *out_index = index; - return ResultSuccess(); - } - - void WaitableManagerHorizonImpl::CancelWait() { - R_ABORT_UNLESS(svc::CancelSynchronization(this->handle)); - } - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_manager_target_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_manager_target_impl.os.horizon.hpp deleted file mode 100644 index ac7ee6b..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_manager_target_impl.os.horizon.hpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 -#include "os_thread_manager.hpp" - -namespace ams::os::impl { - - class WaitableManagerHorizonImpl { - public: - static constexpr size_t MaximumHandleCount = static_cast(ams::svc::ArgumentHandleCountMax); - private: - Handle handle; - private: - Result WaitSynchronizationN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns); - Result ReplyAndReceiveN(s32 *out_index, s32 num, Handle arr[], s32 array_size, s64 ns, Handle reply_target); - public: - void CancelWait(); - - Result WaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num) { - return this->WaitSynchronizationN(out_index, num, arr, array_size, svc::WaitInfinite); - } - - Result TryWaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num) { - return this->WaitSynchronizationN(out_index, num, arr, array_size, 0); - } - - Result TimedWaitAny(s32 *out_index, Handle arr[], s32 array_size, s32 num, TimeSpan ts) { - s64 timeout = ts.GetNanoSeconds(); - if (timeout < 0) { - timeout = 0; - } - return this->WaitSynchronizationN(out_index, num, arr, array_size, timeout); - } - - Result ReplyAndReceive(s32 *out_index, Handle arr[], s32 array_size, s32 num, Handle reply_target) { - return this->ReplyAndReceiveN(out_index, num, arr, array_size, std::numeric_limits::max(), reply_target); - } - - Result TimedReplyAndReceive(s32 *out_index, Handle arr[], s32 array_size, s32 num, Handle reply_target, TimeSpan ts) { - return this->ReplyAndReceiveN(out_index, num, arr, array_size, ts.GetNanoSeconds(), reply_target); - } - - void SetCurrentThreadHandleForCancelWait() { - this->handle = GetCurrentThreadHandle(); - } - - void ClearCurrentThreadHandleForCancelWait() { - this->handle = svc::InvalidHandle; - } - }; - - using WaitableManagerTargetImpl = WaitableManagerHorizonImpl; - -} diff --git a/libraries/libstratosphere/source/os/impl/os_waitable_object_list.hpp b/libraries/libstratosphere/source/os/impl/os_waitable_object_list.hpp deleted file mode 100644 index 786bc66..0000000 --- a/libraries/libstratosphere/source/os/impl/os_waitable_object_list.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 "os_waitable_holder_base.hpp" -#include "os_waitable_manager_impl.hpp" - -namespace ams::os::impl { - - class WaitableObjectList { - public: - using ListType = util::IntrusiveListMemberTraits<&WaitableHolderBase::object_list_node>::ListType; - private: - ListType object_list; - public: - void SignalAllThreads() { - for (WaitableHolderBase &holder_base : this->object_list) { - holder_base.GetManager()->SignalAndWakeupThread(&holder_base); - } - } - - void BroadcastAllThreads() { - for (WaitableHolderBase &holder_base : this->object_list) { - holder_base.GetManager()->SignalAndWakeupThread(nullptr); - } - } - - bool IsEmpty() const { - return this->object_list.empty(); - } - - void LinkWaitableHolder(WaitableHolderBase &holder_base) { - this->object_list.push_back(holder_base); - } - - void UnlinkWaitableHolder(WaitableHolderBase &holder_base) { - this->object_list.erase(this->object_list.iterator_to(holder_base)); - } - }; - -} diff --git a/libraries/libstratosphere/source/os/os_event.cpp b/libraries/libstratosphere/source/os/os_event.cpp index 1132819..63f78b2 100644 --- a/libraries/libstratosphere/source/os/os_event.cpp +++ b/libraries/libstratosphere/source/os/os_event.cpp @@ -15,8 +15,8 @@ */ #include #include "impl/os_timeout_helper.hpp" -#include "impl/os_waitable_object_list.hpp" -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_object_list.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" namespace ams::os { @@ -40,8 +40,8 @@ util::ConstructAt(event->cs_event); util::ConstructAt(event->cv_signaled); - /* Initialize the waitable object list. */ - util::ConstructAt(event->waitable_object_list_storage); + /* Initialize the multi wait object list. */ + util::ConstructAt(event->multi_wait_object_list_storage); /* Initialize member variables. */ event->signaled = signaled; @@ -61,7 +61,7 @@ event->state = EventType::State_NotInitialized; /* Destroy objects. */ - util::DestroyAt(event->waitable_object_list_storage); + util::DestroyAt(event->multi_wait_object_list_storage); util::DestroyAt(event->cv_signaled); util::DestroyAt(event->cs_event); } @@ -89,7 +89,7 @@ } /* Wake up whatever manager, if any. */ - GetReference(event->waitable_object_list_storage).SignalAllThreads(); + GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); } void WaitEvent(EventType *event) { @@ -160,12 +160,12 @@ event->signaled = false; } - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, EventType *event) { + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, EventType *event) { AMS_ASSERT(event->state == EventType::State_Initialized); - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_event_storage, event); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_event_storage, event); - waitable_holder->user_data = 0; + multi_wait_holder->user_data = 0; } } diff --git a/libraries/libstratosphere/source/os/os_interrupt_event.cpp b/libraries/libstratosphere/source/os/os_interrupt_event.cpp index 509ea39..e473252 100644 --- a/libraries/libstratosphere/source/os/os_interrupt_event.cpp +++ b/libraries/libstratosphere/source/os/os_interrupt_event.cpp @@ -15,8 +15,8 @@ */ #include #include "impl/os_interrupt_event_impl.hpp" -#include "impl/os_waitable_holder_impl.hpp" -#include "impl/os_waitable_object_list.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" +#include "impl/os_multiple_wait_object_list.hpp" namespace ams::os { @@ -62,12 +62,12 @@ return GetReference(event->impl).Clear(); } - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, InterruptEventType *event) { + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, InterruptEventType *event) { AMS_ASSERT(event->state == InterruptEventType::State_Initialized); - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_interrupt_event_storage, event); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_interrupt_event_storage, event); - waitable_holder->user_data = 0; + multi_wait_holder->user_data = 0; } } diff --git a/libraries/libstratosphere/source/os/os_message_queue.cpp b/libraries/libstratosphere/source/os/os_message_queue.cpp index bde4dfa..4902411 100644 --- a/libraries/libstratosphere/source/os/os_message_queue.cpp +++ b/libraries/libstratosphere/source/os/os_message_queue.cpp @@ -15,8 +15,8 @@ */ #include #include "impl/os_timeout_helper.hpp" -#include "impl/os_waitable_object_list.hpp" -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_object_list.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" #include "impl/os_message_queue_helper.hpp" namespace ams::os { @@ -319,20 +319,20 @@ return true; } - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, MessageQueueType *mq, MessageQueueWaitType type) { + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, MessageQueueType *mq, MessageQueueWaitType type) { AMS_ASSERT(mq->state == MessageQueueType::State_Initialized); switch (type) { case MessageQueueWaitType::ForNotFull: - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_mq_for_not_full_storage, mq); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_mq_for_not_full_storage, mq); break; case MessageQueueWaitType::ForNotEmpty: - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_mq_for_not_empty_storage, mq); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_mq_for_not_empty_storage, mq); break; AMS_UNREACHABLE_DEFAULT_CASE(); } - waitable_holder->user_data = 0; + multi_wait_holder->user_data = 0; } } diff --git a/libraries/libstratosphere/source/os/os_multiple_wait.cpp b/libraries/libstratosphere/source/os/os_multiple_wait.cpp new file mode 100644 index 0000000..10ba242 --- /dev/null +++ b/libraries/libstratosphere/source/os/os_multiple_wait.cpp @@ -0,0 +1,152 @@ +/* + * 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 "impl/os_multiple_wait_impl.hpp" +#include "impl/os_multiple_wait_holder_base.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" + +namespace ams::os { + + namespace { + + ALWAYS_INLINE impl::MultiWaitImpl &GetMultiWaitImpl(MultiWaitType *multi_wait) { + return GetReference(multi_wait->impl_storage); + } + + ALWAYS_INLINE MultiWaitHolderType *CastToMultiWaitHolder(impl::MultiWaitHolderBase *base) { + return reinterpret_cast(base); + } + + } + + void InitializeMultiWait(MultiWaitType *multi_wait) { + /* Initialize storage. */ + util::ConstructAt(multi_wait->impl_storage); + + /* Mark initialized. */ + multi_wait->state = MultiWaitType::State_Initialized; + } + + void FinalizeMultiWait(MultiWaitType *multi_wait) { + auto &impl = GetMultiWaitImpl(multi_wait); + + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); + AMS_ASSERT(impl.IsEmpty()); + AMS_UNUSED(impl); + + /* Mark not initialized. */ + multi_wait->state = MultiWaitType::State_NotInitialized; + + /* Destroy. */ + util::DestroyAt(multi_wait->impl_storage); + } + + MultiWaitHolderType *WaitAny(MultiWaitType *multi_wait) { + auto &impl = GetMultiWaitImpl(multi_wait); + + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); + AMS_ASSERT(!impl.IsEmpty()); + + auto *holder = CastToMultiWaitHolder(impl.WaitAny()); + AMS_ASSERT(holder != nullptr); + return holder; + } + + MultiWaitHolderType *TryWaitAny(MultiWaitType *multi_wait) { + auto &impl = GetMultiWaitImpl(multi_wait); + + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); + AMS_ASSERT(!impl.IsEmpty()); + + auto *holder = CastToMultiWaitHolder(impl.TryWaitAny()); + return holder; + } + + MultiWaitHolderType *TimedWaitAny(MultiWaitType *multi_wait, TimeSpan timeout) { + auto &impl = GetMultiWaitImpl(multi_wait); + + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); + AMS_ASSERT(!impl.IsEmpty()); + AMS_ASSERT(timeout.GetNanoSeconds() >= 0); + + auto *holder = CastToMultiWaitHolder(impl.TimedWaitAny(timeout)); + return holder; + } + + void FinalizeMultiWaitHolder(MultiWaitHolderType *holder) { + auto *holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); + + AMS_ASSERT(!holder_base->IsLinked()); + + std::destroy_at(holder_base); + } + + void LinkMultiWaitHolder(MultiWaitType *multi_wait, MultiWaitHolderType *holder) { + auto &impl = GetMultiWaitImpl(multi_wait); + auto *holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); + + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); + AMS_ASSERT(!holder_base->IsLinked()); + + impl.LinkMultiWaitHolder(*holder_base); + holder_base->SetMultiWait(&impl); + } + + void UnlinkMultiWaitHolder(MultiWaitHolderType *holder) { + auto *holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); + + /* Don't allow unlinking of an unlinked holder. */ + AMS_ABORT_UNLESS(holder_base->IsLinked()); + + holder_base->GetMultiWait()->UnlinkMultiWaitHolder(*holder_base); + holder_base->SetMultiWait(nullptr); + } + + void UnlinkAllMultiWaitHolder(MultiWaitType *multi_wait) { + auto &impl = GetMultiWaitImpl(multi_wait); + + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); + + return impl.UnlinkAll(); + } + + void MoveAllMultiWaitHolder(MultiWaitType *_dst, MultiWaitType *_src) { + auto &dst = GetMultiWaitImpl(_dst); + auto &src = GetMultiWaitImpl(_src); + + AMS_ASSERT(_dst->state == MultiWaitType::State_Initialized); + AMS_ASSERT(_src->state == MultiWaitType::State_Initialized); + + return dst.MoveAllFrom(src); + } + + void SetMultiWaitHolderUserData(MultiWaitHolderType *holder, uintptr_t user_data) { + holder->user_data = user_data; + } + + uintptr_t GetMultiWaitHolderUserData(const MultiWaitHolderType *holder) { + return holder->user_data; + } + + void InitializeMultiWaitHolder(MultiWaitHolderType *holder, Handle handle) { + AMS_ASSERT(handle != svc::InvalidHandle); + + util::ConstructAt(GetReference(holder->impl_storage).holder_of_handle_storage, handle); + + holder->user_data = 0; + } + +} diff --git a/libraries/libstratosphere/source/os/os_sdk_reply_and_receive.cpp b/libraries/libstratosphere/source/os/os_sdk_reply_and_receive.cpp index a0242cd..3c9016d 100644 --- a/libraries/libstratosphere/source/os/os_sdk_reply_and_receive.cpp +++ b/libraries/libstratosphere/source/os/os_sdk_reply_and_receive.cpp @@ -14,32 +14,32 @@ * along with this program. If not, see . */ #include -#include "impl/os_waitable_manager_impl.hpp" -#include "impl/os_waitable_holder_base.hpp" -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_impl.hpp" +#include "impl/os_multiple_wait_holder_base.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" namespace ams::os { namespace { - ALWAYS_INLINE impl::WaitableManagerImpl &GetWaitableManagerImpl(WaitableManagerType *manager) { - return GetReference(manager->impl_storage); + ALWAYS_INLINE impl::MultiWaitImpl &GetMultiWaitImpl(MultiWaitType *multi_wait) { + return GetReference(multi_wait->impl_storage); } - ALWAYS_INLINE WaitableHolderType *CastToWaitableHolder(impl::WaitableHolderBase *base) { - return reinterpret_cast(base); + ALWAYS_INLINE MultiWaitHolderType *CastToMultiWaitHolder(impl::MultiWaitHolderBase *base) { + return reinterpret_cast(base); } } - Result SdkReplyAndReceive(os::WaitableHolderType **out, Handle reply_target, WaitableManagerType *manager) { - auto &impl = GetWaitableManagerImpl(manager); + Result SdkReplyAndReceive(os::MultiWaitHolderType **out, Handle reply_target, MultiWaitType *multi_wait) { + auto &impl = GetMultiWaitImpl(multi_wait); - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); + AMS_ASSERT(multi_wait->state == MultiWaitType::State_Initialized); AMS_ASSERT(!impl.IsEmpty()); - impl::WaitableHolderBase *holder_base; - ON_SCOPE_EXIT { *out = CastToWaitableHolder(holder_base); }; + impl::MultiWaitHolderBase *holder_base; + ON_SCOPE_EXIT { *out = CastToMultiWaitHolder(holder_base); }; return impl.ReplyAndReceive(std::addressof(holder_base), reply_target); } diff --git a/libraries/libstratosphere/source/os/os_semaphore.cpp b/libraries/libstratosphere/source/os/os_semaphore.cpp index 3c99c75..e48df50 100644 --- a/libraries/libstratosphere/source/os/os_semaphore.cpp +++ b/libraries/libstratosphere/source/os/os_semaphore.cpp @@ -14,8 +14,8 @@ * along with this program. If not, see . */ #include -#include "impl/os_waitable_object_list.hpp" -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_object_list.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" #include "impl/os_timeout_helper.hpp" namespace ams::os { @@ -142,12 +142,12 @@ return sema->count; } - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, SemaphoreType *sema) { + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, SemaphoreType *sema) { AMS_ASSERT(sema->state == SemaphoreType::State_Initialized); - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_semaphore_storage, sema); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_semaphore_storage, sema); - waitable_holder->user_data = 0; + multi_wait_holder->user_data = 0; } } diff --git a/libraries/libstratosphere/source/os/os_system_event.cpp b/libraries/libstratosphere/source/os/os_system_event.cpp index e828356..955f4d8 100644 --- a/libraries/libstratosphere/source/os/os_system_event.cpp +++ b/libraries/libstratosphere/source/os/os_system_event.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #include -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" #include "impl/os_inter_process_event.hpp" #include "impl/os_timeout_helper.hpp" @@ -119,13 +119,13 @@ } } - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, SystemEventType *event) { + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, SystemEventType *event) { switch (event->state) { case SystemEventType::State_InitializedAsInterProcessEvent: - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_inter_process_event_storage, std::addressof(event->inter_process_event)); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_inter_process_event_storage, std::addressof(event->inter_process_event)); break; case SystemEventType::State_InitializedAsEvent: - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_event_storage, std::addressof(event->event)); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_event_storage, std::addressof(event->event)); break; AMS_UNREACHABLE_DEFAULT_CASE(); } diff --git a/libraries/libstratosphere/source/os/os_thread.cpp b/libraries/libstratosphere/source/os/os_thread.cpp index 45a8b69..89b56a8 100644 --- a/libraries/libstratosphere/source/os/os_thread.cpp +++ b/libraries/libstratosphere/source/os/os_thread.cpp @@ -16,7 +16,7 @@ #include #include "impl/os_thread_manager.hpp" #include "impl/os_timeout_helper.hpp" -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" namespace ams::os { diff --git a/libraries/libstratosphere/source/os/os_timer_event.cpp b/libraries/libstratosphere/source/os/os_timer_event.cpp index 0a632de..e68189a 100644 --- a/libraries/libstratosphere/source/os/os_timer_event.cpp +++ b/libraries/libstratosphere/source/os/os_timer_event.cpp @@ -17,8 +17,8 @@ #include "impl/os_timer_event_helper.hpp" #include "impl/os_tick_manager.hpp" #include "impl/os_timeout_helper.hpp" -#include "impl/os_waitable_object_list.hpp" -#include "impl/os_waitable_holder_impl.hpp" +#include "impl/os_multiple_wait_object_list.hpp" +#include "impl/os_multiple_wait_holder_impl.hpp" namespace ams::os { @@ -49,7 +49,7 @@ } /* Wake up whatever manager, if any. */ - GetReference(event->waitable_object_list_storage).SignalAllThreads(); + GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); } } @@ -59,8 +59,8 @@ util::ConstructAt(event->cs_timer_event); util::ConstructAt(event->cv_signaled); - /* Initialize the waitable object list. */ - util::ConstructAt(event->waitable_object_list_storage); + /* Initialize the multi wait object list. */ + util::ConstructAt(event->multi_wait_object_list_storage); /* Initialize member variables. */ event->clear_mode = static_cast(clear_mode); @@ -83,7 +83,7 @@ event->state = TimerEventType::State_NotInitialized; /* Destroy objects. */ - util::DestroyAt(event->waitable_object_list_storage); + util::DestroyAt(event->multi_wait_object_list_storage); util::DestroyAt(event->cv_signaled); util::DestroyAt(event->cs_timer_event); } @@ -110,7 +110,7 @@ GetReference(event->cv_signaled).Broadcast(); /* Wake up whatever manager, if any. */ - GetReference(event->waitable_object_list_storage).SignalAllThreads(); + GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); } } @@ -137,7 +137,7 @@ GetReference(event->cv_signaled).Broadcast(); /* Wake up whatever manager, if any. */ - GetReference(event->waitable_object_list_storage).SignalAllThreads(); + GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); } } @@ -154,7 +154,7 @@ GetReference(event->cv_signaled).Broadcast(); /* Wake up whatever manager, if any. */ - GetReference(event->waitable_object_list_storage).SignalAllThreads(); + GetReference(event->multi_wait_object_list_storage).SignalAllThreads(); } } @@ -252,12 +252,12 @@ } } - void InitializeWaitableHolder(WaitableHolderType *waitable_holder, TimerEventType *event) { + void InitializeMultiWaitHolder(MultiWaitHolderType *multi_wait_holder, TimerEventType *event) { AMS_ASSERT(event->state == EventType::State_Initialized); - util::ConstructAt(GetReference(waitable_holder->impl_storage).holder_of_timer_event_storage, event); + util::ConstructAt(GetReference(multi_wait_holder->impl_storage).holder_of_timer_event_storage, event); - waitable_holder->user_data = 0; + multi_wait_holder->user_data = 0; } } diff --git a/libraries/libstratosphere/source/os/os_waitable.cpp b/libraries/libstratosphere/source/os/os_waitable.cpp deleted file mode 100644 index 2df27e6..0000000 --- a/libraries/libstratosphere/source/os/os_waitable.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/* - * 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 "impl/os_waitable_manager_impl.hpp" -#include "impl/os_waitable_holder_base.hpp" -#include "impl/os_waitable_holder_impl.hpp" - -namespace ams::os { - - namespace { - - ALWAYS_INLINE impl::WaitableManagerImpl &GetWaitableManagerImpl(WaitableManagerType *manager) { - return GetReference(manager->impl_storage); - } - - ALWAYS_INLINE WaitableHolderType *CastToWaitableHolder(impl::WaitableHolderBase *base) { - return reinterpret_cast(base); - } - - } - - void InitializeWaitableManager(WaitableManagerType *manager) { - /* Initialize storage. */ - util::ConstructAt(manager->impl_storage); - - /* Mark initialized. */ - manager->state = WaitableManagerType::State_Initialized; - } - - void FinalizeWaitableManager(WaitableManagerType *manager) { - auto &impl = GetWaitableManagerImpl(manager); - - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); - AMS_ASSERT(impl.IsEmpty()); - AMS_UNUSED(impl); - - /* Mark not initialized. */ - manager->state = WaitableManagerType::State_NotInitialized; - - /* Destroy. */ - util::DestroyAt(manager->impl_storage); - } - - WaitableHolderType *WaitAny(WaitableManagerType *manager) { - auto &impl = GetWaitableManagerImpl(manager); - - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); - AMS_ASSERT(!impl.IsEmpty()); - - auto *holder = CastToWaitableHolder(impl.WaitAny()); - AMS_ASSERT(holder != nullptr); - return holder; - } - - WaitableHolderType *TryWaitAny(WaitableManagerType *manager) { - auto &impl = GetWaitableManagerImpl(manager); - - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); - AMS_ASSERT(!impl.IsEmpty()); - - auto *holder = CastToWaitableHolder(impl.TryWaitAny()); - return holder; - } - - WaitableHolderType *TimedWaitAny(WaitableManagerType *manager, TimeSpan timeout) { - auto &impl = GetWaitableManagerImpl(manager); - - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); - AMS_ASSERT(!impl.IsEmpty()); - AMS_ASSERT(timeout.GetNanoSeconds() >= 0); - - auto *holder = CastToWaitableHolder(impl.TimedWaitAny(timeout)); - return holder; - } - - void FinalizeWaitableHolder(WaitableHolderType *holder) { - auto *holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); - - AMS_ASSERT(!holder_base->IsLinkedToManager()); - - std::destroy_at(holder_base); - } - - void LinkWaitableHolder(WaitableManagerType *manager, WaitableHolderType *holder) { - auto &impl = GetWaitableManagerImpl(manager); - auto *holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); - - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); - AMS_ASSERT(!holder_base->IsLinkedToManager()); - - impl.LinkWaitableHolder(*holder_base); - holder_base->SetManager(&impl); - } - - void UnlinkWaitableHolder(WaitableHolderType *holder) { - auto *holder_base = reinterpret_cast(GetPointer(holder->impl_storage)); - - /* Don't allow unlinking of an unlinked holder. */ - AMS_ABORT_UNLESS(holder_base->IsLinkedToManager()); - - holder_base->GetManager()->UnlinkWaitableHolder(*holder_base); - holder_base->SetManager(nullptr); - } - - void UnlinkAllWaitableHolder(WaitableManagerType *manager) { - auto &impl = GetWaitableManagerImpl(manager); - - AMS_ASSERT(manager->state == WaitableManagerType::State_Initialized); - - return impl.UnlinkAll(); - } - - void MoveAllWaitableHolder(WaitableManagerType *_dst, WaitableManagerType *_src) { - auto &dst = GetWaitableManagerImpl(_dst); - auto &src = GetWaitableManagerImpl(_src); - - AMS_ASSERT(_dst->state == WaitableManagerType::State_Initialized); - AMS_ASSERT(_src->state == WaitableManagerType::State_Initialized); - - return dst.MoveAllFrom(src); - } - - void SetWaitableHolderUserData(WaitableHolderType *holder, uintptr_t user_data) { - holder->user_data = user_data; - } - - uintptr_t GetWaitableHolderUserData(const WaitableHolderType *holder) { - return holder->user_data; - } - - void InitializeWaitableHolder(WaitableHolderType *holder, Handle handle) { - AMS_ASSERT(handle != svc::InvalidHandle); - - util::ConstructAt(GetReference(holder->impl_storage).holder_of_handle_storage, handle); - - holder->user_data = 0; - } - -} diff --git a/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_type.os.horizon.hpp b/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_type.os.horizon.hpp index f5ba193..6b78bd2 100644 --- a/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_type.os.horizon.hpp +++ b/libraries/libstratosphere/source/osdbg/impl/osdbg_thread_type.os.horizon.hpp @@ -26,7 +26,7 @@ struct ThreadTypeIlp32 { AlignedStorageIlp32<0, 2, alignof(u32)> _all_threads_node; - AlignedStorageIlp32<0, 2, alignof(u32)> _waitable_object_list; + AlignedStorageIlp32<0, 2, alignof(u32)> _multi_wait_object_list; u32 _padding[4]; u8 _state; bool _stack_is_aliased; @@ -55,7 +55,7 @@ struct ThreadTypeIlp32Version0 { AlignedStorageIlp32<0, 2, alignof(u32)> _all_threads_node; - AlignedStorageIlp32<0, 2, alignof(u32)> _waitable_object_list; + AlignedStorageIlp32<0, 2, alignof(u32)> _multi_wait_object_list; u32 _padding[4]; u8 _state; bool _stack_is_aliased; @@ -82,7 +82,7 @@ struct ThreadTypeLp64 { AlignedStorageLp64<0, 2, alignof(u64)> _all_threads_node; - AlignedStorageLp64<0, 2, alignof(u64)> _waitable_object_list; + AlignedStorageLp64<0, 2, alignof(u64)> _multi_wait_object_list; u64 _padding[4]; u8 _state; bool _stack_is_aliased; @@ -110,7 +110,7 @@ struct ThreadTypeLp64Version0 { AlignedStorageLp64<0, 2, alignof(u64)> _all_threads_node; - AlignedStorageLp64<0, 2, alignof(u64)> _waitable_object_list; + AlignedStorageLp64<0, 2, alignof(u64)> _multi_wait_object_list; u64 _padding[4]; u8 _state; bool _stack_is_aliased; diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp index 113c47f..a66c42b 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.cpp @@ -41,12 +41,12 @@ } - void AttachWaitableHolderForAccept(os::WaitableHolderType *holder, Handle port) { - return os::InitializeWaitableHolder(holder, port); + void AttachMultiWaitHolderForAccept(os::MultiWaitHolderType *holder, Handle port) { + return os::InitializeMultiWaitHolder(holder, port); } - void AttachWaitableHolderForReply(os::WaitableHolderType *holder, Handle request) { - return os::InitializeWaitableHolder(holder, request); + void AttachMultiWaitHolderForReply(os::MultiWaitHolderType *holder, Handle request) { + return os::InitializeMultiWaitHolder(holder, request); } Result Receive(ReceiveResult *out_recv_result, Handle session_handle, const cmif::PointerAndSize &message_buffer) { diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp index c5b5c1c..87e8ca2 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_manager.cpp @@ -32,37 +32,37 @@ return ResultSuccess(); } - void ServerManagerBase::RegisterSessionToWaitList(ServerSession *session) { + void ServerManagerBase::RegisterServerSessionToWait(ServerSession *session) { session->has_received = false; /* Set user data tag. */ - os::SetWaitableHolderUserData(session, static_cast(UserDataTag::Session)); + os::SetMultiWaitHolderUserData(session, static_cast(UserDataTag::Session)); - this->RegisterToWaitList(session); + this->LinkToDeferredList(session); } - void ServerManagerBase::RegisterToWaitList(os::WaitableHolderType *holder) { - std::scoped_lock lk(this->waitlist_mutex); - os::LinkWaitableHolder(std::addressof(this->waitlist), holder); + void ServerManagerBase::LinkToDeferredList(os::MultiWaitHolderType *holder) { + std::scoped_lock lk(this->deferred_list_mutex); + os::LinkMultiWaitHolder(std::addressof(this->deferred_list), holder); this->notify_event.Signal(); } - void ServerManagerBase::ProcessWaitList() { - std::scoped_lock lk(this->waitlist_mutex); - os::MoveAllWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->waitlist)); + void ServerManagerBase::LinkDeferred() { + std::scoped_lock lk(this->deferred_list_mutex); + os::MoveAllMultiWaitHolder(std::addressof(this->multi_wait), std::addressof(this->deferred_list)); } - os::WaitableHolderType *ServerManagerBase::WaitSignaled() { - std::scoped_lock lk(this->waitable_selection_mutex); + os::MultiWaitHolderType *ServerManagerBase::WaitSignaled() { + std::scoped_lock lk(this->selection_mutex); while (true) { - this->ProcessWaitList(); - auto selected = os::WaitAny(std::addressof(this->waitable_manager)); + this->LinkDeferred(); + auto selected = os::WaitAny(std::addressof(this->multi_wait)); if (selected == &this->request_stop_event_holder) { return nullptr; } else if (selected == &this->notify_event_holder) { this->notify_event.Clear(); } else { - os::UnlinkWaitableHolder(selected); + os::UnlinkMultiWaitHolder(selected); return selected; } } @@ -76,19 +76,19 @@ this->request_stop_event.Signal(); } - void ServerManagerBase::AddUserWaitableHolder(os::WaitableHolderType *waitable) { - const auto user_data_tag = static_cast(os::GetWaitableHolderUserData(waitable)); + void ServerManagerBase::AddUserMultiWaitHolder(os::MultiWaitHolderType *holder) { + const auto user_data_tag = static_cast(os::GetMultiWaitHolderUserData(holder)); AMS_ABORT_UNLESS(user_data_tag != UserDataTag::Server); AMS_ABORT_UNLESS(user_data_tag != UserDataTag::MitmServer); AMS_ABORT_UNLESS(user_data_tag != UserDataTag::Session); - this->RegisterToWaitList(waitable); + this->LinkToDeferredList(holder); } - Result ServerManagerBase::ProcessForServer(os::WaitableHolderType *holder) { - AMS_ABORT_UNLESS(static_cast(os::GetWaitableHolderUserData(holder)) == UserDataTag::Server); + Result ServerManagerBase::ProcessForServer(os::MultiWaitHolderType *holder) { + AMS_ABORT_UNLESS(static_cast(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::Server); Server *server = static_cast(holder); - ON_SCOPE_EXIT { this->RegisterToWaitList(server); }; + ON_SCOPE_EXIT { this->LinkToDeferredList(server); }; /* Create new session. */ if (server->static_object) { @@ -98,18 +98,18 @@ } } - Result ServerManagerBase::ProcessForMitmServer(os::WaitableHolderType *holder) { - AMS_ABORT_UNLESS(static_cast(os::GetWaitableHolderUserData(holder)) == UserDataTag::MitmServer); + Result ServerManagerBase::ProcessForMitmServer(os::MultiWaitHolderType *holder) { + AMS_ABORT_UNLESS(static_cast(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::MitmServer); Server *server = static_cast(holder); - ON_SCOPE_EXIT { this->RegisterToWaitList(server); }; + ON_SCOPE_EXIT { this->LinkToDeferredList(server); }; /* Create resources for new session. */ return this->OnNeedsToAccept(server->index, server); } - Result ServerManagerBase::ProcessForSession(os::WaitableHolderType *holder) { - AMS_ABORT_UNLESS(static_cast(os::GetWaitableHolderUserData(holder)) == UserDataTag::Session); + Result ServerManagerBase::ProcessForSession(os::MultiWaitHolderType *holder) { + AMS_ABORT_UNLESS(static_cast(os::GetMultiWaitHolderUserData(holder)) == UserDataTag::Session); ServerSession *session = static_cast(holder); @@ -133,8 +133,8 @@ return ResultSuccess(); } - Result ServerManagerBase::Process(os::WaitableHolderType *holder) { - switch (static_cast(os::GetWaitableHolderUserData(holder))) { + Result ServerManagerBase::Process(os::MultiWaitHolderType *holder) { + switch (static_cast(os::GetMultiWaitHolderUserData(holder))) { case UserDataTag::Server: return this->ProcessForServer(holder); case UserDataTag::MitmServer: @@ -146,12 +146,12 @@ } bool ServerManagerBase::WaitAndProcessImpl() { - auto waitable = this->WaitSignaled(); - if (!waitable) { + if (auto *signaled_holder = this->WaitSignaled(); signaled_holder != nullptr) { + R_ABORT_UNLESS(this->Process(signaled_holder)); + return true; + } else { return false; } - R_ABORT_UNLESS(this->Process(waitable)); - return true; } void ServerManagerBase::WaitAndProcess() { diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp index 0693625..983c4e0 100644 --- a/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_server_session_manager.cpp @@ -78,7 +78,7 @@ void ServerSessionManager::CloseSessionImpl(ServerSession *session) { const Handle session_handle = session->session_handle; - os::FinalizeWaitableHolder(session); + os::FinalizeMultiWaitHolder(session); this->DestroySession(session); R_ABORT_UNLESS(svcCloseHandle(session_handle)); } @@ -92,7 +92,7 @@ session_memory->saved_message = this->GetSessionSavedMessageBuffer(session_memory); /* Register to wait list. */ - this->RegisterSessionToWaitList(session_memory); + this->RegisterServerSessionToWait(session_memory); return ResultSuccess(); } @@ -123,7 +123,7 @@ session_memory->pointer_buffer = cmif::PointerAndSize(session_memory->pointer_buffer.GetAddress(), session_memory->forward_service->pointer_buffer_size); /* Register to wait list. */ - this->RegisterSessionToWaitList(session_memory); + this->RegisterServerSessionToWait(session_memory); return ResultSuccess(); } @@ -233,7 +233,7 @@ } R_END_TRY_CATCH; /* We succeeded, so we can process future messages on this session. */ - this->RegisterSessionToWaitList(session); + this->RegisterServerSessionToWait(session); return ResultSuccess(); } } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp index 4deae15..3cdf0fa 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_device_detector.cpp @@ -71,18 +71,18 @@ os::SystemEventType gpio_event; R_ABORT_UNLESS(gpio::BindInterrupt(std::addressof(gpio_event), std::addressof(this->gpio_pad_session))); - /* Initialize and link waitable holders. */ - os::WaitableManagerType wait_manager; - os::WaitableHolderType detector_thread_end_holder; - os::WaitableHolderType request_sleep_wake_event_holder; - os::WaitableHolderType gpio_event_holder; - os::InitializeWaitableManager(std::addressof(wait_manager)); - os::InitializeWaitableHolder(std::addressof(detector_thread_end_holder), std::addressof(this->detector_thread_end_event)); - os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(detector_thread_end_holder)); - os::InitializeWaitableHolder(std::addressof(request_sleep_wake_event_holder), std::addressof(this->request_sleep_wake_event)); - os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(request_sleep_wake_event_holder)); - os::InitializeWaitableHolder(std::addressof(gpio_event_holder), std::addressof(gpio_event)); - os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(gpio_event_holder)); + /* Initialize and link multi wait/holders. */ + os::MultiWaitType multi_wait; + os::MultiWaitHolderType detector_thread_end_holder; + os::MultiWaitHolderType request_sleep_wake_event_holder; + os::MultiWaitHolderType gpio_event_holder; + os::InitializeMultiWait(std::addressof(multi_wait)); + os::InitializeMultiWaitHolder(std::addressof(detector_thread_end_holder), std::addressof(this->detector_thread_end_event)); + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(detector_thread_end_holder)); + os::InitializeMultiWaitHolder(std::addressof(request_sleep_wake_event_holder), std::addressof(this->request_sleep_wake_event)); + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(request_sleep_wake_event_holder)); + os::InitializeMultiWaitHolder(std::addressof(gpio_event_holder), std::addressof(gpio_event)); + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(gpio_event_holder)); /* Wait before detecting the initial state of the card. */ os::SleepThread(TimeSpan::FromMilliSeconds(this->gpio_debounce_ms)); @@ -99,7 +99,7 @@ /* Wait, servicing our events. */ while (true) { /* Get the signaled holder. */ - os::WaitableHolderType *signaled_holder = os::WaitAny(std::addressof(wait_manager)); + os::MultiWaitHolderType *signaled_holder = os::WaitAny(std::addressof(multi_wait)); /* Process the holder. */ bool insert_change = false; @@ -115,13 +115,13 @@ os::SignalEvent(std::addressof(this->acknowledge_sleep_awake_event)); /* Temporarily unlink our interrupt event. */ - os::UnlinkWaitableHolder(std::addressof(gpio_event_holder)); + os::UnlinkMultiWaitHolder(std::addressof(gpio_event_holder)); /* Wait to be signaled. */ - signaled_holder = os::WaitAny(std::addressof(wait_manager)); + signaled_holder = os::WaitAny(std::addressof(multi_wait)); /* Link our interrupt event back in. */ - os::LinkWaitableHolder(std::addressof(wait_manager), std::addressof(gpio_event_holder)); + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(gpio_event_holder)); /* We're awake again. Either because we should exit, or because we were asked to wake up. */ os::ClearEvent(std::addressof(this->request_sleep_wake_event)); @@ -170,14 +170,14 @@ /* Disable interrupts to our gpio event. */ gpio::SetInterruptEnable(std::addressof(this->gpio_pad_session), false); - /* Finalize and unlink waitable holders. */ - os::UnlinkWaitableHolder(std::addressof(gpio_event_holder)); - os::FinalizeWaitableHolder(std::addressof(gpio_event_holder)); - os::UnlinkWaitableHolder(std::addressof(request_sleep_wake_event_holder)); - os::FinalizeWaitableHolder(std::addressof(request_sleep_wake_event_holder)); - os::UnlinkWaitableHolder(std::addressof(detector_thread_end_holder)); - os::FinalizeWaitableHolder(std::addressof(detector_thread_end_holder)); - os::FinalizeWaitableManager(std::addressof(wait_manager)); + /* Finalize and unlink multi wait/holders. */ + os::UnlinkMultiWaitHolder(std::addressof(gpio_event_holder)); + os::FinalizeMultiWaitHolder(std::addressof(gpio_event_holder)); + os::UnlinkMultiWaitHolder(std::addressof(request_sleep_wake_event_holder)); + os::FinalizeMultiWaitHolder(std::addressof(request_sleep_wake_event_holder)); + os::UnlinkMultiWaitHolder(std::addressof(detector_thread_end_holder)); + os::FinalizeMultiWaitHolder(std::addressof(detector_thread_end_holder)); + os::FinalizeMultiWait(std::addressof(multi_wait)); /* Finalize the gpio session. */ gpio::UnbindInterrupt(std::addressof(this->gpio_pad_session)); diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.cpp index f03d153..fd6ec10 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.cpp @@ -173,7 +173,7 @@ this->EnsureControl(); /* Wait for the interrupt to be signaled. */ - os::WaitableHolderType *signaled_holder = os::TimedWaitAny(std::addressof(this->waitable_manager), TimeSpan::FromMilliSeconds(timeout_ms)); + os::MultiWaitHolderType *signaled_holder = os::TimedWaitAny(std::addressof(this->multi_wait), TimeSpan::FromMilliSeconds(timeout_ms)); if (signaled_holder == std::addressof(this->interrupt_event_holder)) { /* We received the interrupt. */ return ResultSuccess(); @@ -781,15 +781,15 @@ void SdHostStandardController::Initialize() { #if defined(AMS_SDMMC_USE_OS_EVENTS) { - os::InitializeWaitableManager(std::addressof(this->waitable_manager)); + os::InitializeMultiWait(std::addressof(this->multi_wait)); AMS_ABORT_UNLESS(this->interrupt_event != nullptr); - os::InitializeWaitableHolder(std::addressof(this->interrupt_event_holder), this->interrupt_event); - os::LinkWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->interrupt_event_holder)); + os::InitializeMultiWaitHolder(std::addressof(this->interrupt_event_holder), this->interrupt_event); + os::LinkMultiWaitHolder(std::addressof(this->multi_wait), std::addressof(this->interrupt_event_holder)); if (this->removed_event != nullptr) { - os::InitializeWaitableHolder(std::addressof(this->removed_event_holder), this->removed_event); - os::LinkWaitableHolder(std::addressof(this->waitable_manager), std::addressof(this->removed_event_holder)); + os::InitializeMultiWaitHolder(std::addressof(this->removed_event_holder), this->removed_event); + os::LinkMultiWaitHolder(std::addressof(this->multi_wait), std::addressof(this->removed_event_holder)); } } #endif @@ -799,14 +799,14 @@ #if defined(AMS_SDMMC_USE_OS_EVENTS) { if (this->removed_event != nullptr) { - os::UnlinkWaitableHolder(std::addressof(this->removed_event_holder)); - os::FinalizeWaitableHolder(std::addressof(this->removed_event_holder)); + os::UnlinkMultiWaitHolder(std::addressof(this->removed_event_holder)); + os::FinalizeMultiWaitHolder(std::addressof(this->removed_event_holder)); } - os::UnlinkWaitableHolder(std::addressof(this->interrupt_event_holder)); - os::FinalizeWaitableHolder(std::addressof(this->interrupt_event_holder)); + os::UnlinkMultiWaitHolder(std::addressof(this->interrupt_event_holder)); + os::FinalizeMultiWaitHolder(std::addressof(this->interrupt_event_holder)); - os::FinalizeWaitableManager(std::addressof(this->waitable_manager)); + os::FinalizeMultiWait(std::addressof(this->multi_wait)); } #endif } diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp index 7bdf0a3..b432357 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_sd_host_standard_controller.hpp @@ -39,11 +39,11 @@ #endif #if defined(AMS_SDMMC_USE_OS_EVENTS) - os::WaitableManagerType waitable_manager; + os::MultiWaitType multi_wait; os::InterruptEventType *interrupt_event; - os::WaitableHolderType interrupt_event_holder; + os::MultiWaitHolderType interrupt_event_holder; os::EventType *removed_event; - os::WaitableHolderType removed_event_holder; + os::MultiWaitHolderType removed_event_holder; #endif u64 next_sdma_address; diff --git a/stratosphere/fatal/source/fatal_config.cpp b/stratosphere/fatal/source/fatal_config.cpp index 3a04b92..5ce0e53 100644 --- a/stratosphere/fatal/source/fatal_config.cpp +++ b/stratosphere/fatal/source/fatal_config.cpp @@ -32,19 +32,19 @@ /* Global event. */ os::SystemEventType g_fatal_dirty_event; - os::WaitableHolderType g_fatal_dirty_waitable_holder; + os::MultiWaitHolderType g_fatal_dirty_multi_wait_holder; bool g_initialized; } - os::WaitableHolderType *GetFatalDirtyWaitableHolder() { + os::MultiWaitHolderType *GetFatalDirtyMultiWaitHolder() { if (AMS_UNLIKELY(!g_initialized)) { os::AttachReadableHandleToSystemEvent(std::addressof(g_fatal_dirty_event), GetFatalDirtyEventReadableHandle(), true, os::EventClearMode_ManualClear); - os::InitializeWaitableHolder(std::addressof(g_fatal_dirty_waitable_holder), std::addressof(g_fatal_dirty_event)); - os::SetWaitableHolderUserData(std::addressof(g_fatal_dirty_waitable_holder), reinterpret_cast(std::addressof(g_fatal_dirty_waitable_holder))); + os::InitializeMultiWaitHolder(std::addressof(g_fatal_dirty_multi_wait_holder), std::addressof(g_fatal_dirty_event)); + os::SetMultiWaitHolderUserData(std::addressof(g_fatal_dirty_multi_wait_holder), reinterpret_cast(std::addressof(g_fatal_dirty_multi_wait_holder))); g_initialized = true; } - return std::addressof(g_fatal_dirty_waitable_holder); + return std::addressof(g_fatal_dirty_multi_wait_holder); } void OnFatalDirtyEvent() { diff --git a/stratosphere/fatal/source/fatal_config.hpp b/stratosphere/fatal/source/fatal_config.hpp index 2e0941c..1244a5f 100644 --- a/stratosphere/fatal/source/fatal_config.hpp +++ b/stratosphere/fatal/source/fatal_config.hpp @@ -88,7 +88,7 @@ } }; - os::WaitableHolderType *GetFatalDirtyWaitableHolder(); + os::MultiWaitHolderType *GetFatalDirtyMultiWaitHolder(); void OnFatalDirtyEvent(); const FatalConfig &GetFatalConfig(); diff --git a/stratosphere/fatal/source/fatal_main.cpp b/stratosphere/fatal/source/fatal_main.cpp index 5e10fb0..b2531b4 100644 --- a/stratosphere/fatal/source/fatal_main.cpp +++ b/stratosphere/fatal/source/fatal_main.cpp @@ -218,8 +218,8 @@ R_ABORT_UNLESS(g_server_manager.RegisterObjectForServer(g_private_service_object.GetShared(), PrivateServiceName, PrivateMaxSessions)); /* Add dirty event holder. */ - auto *dirty_event_holder = ams::fatal::srv::GetFatalDirtyWaitableHolder(); - g_server_manager.AddUserWaitableHolder(dirty_event_holder); + auto *dirty_event_holder = ams::fatal::srv::GetFatalDirtyMultiWaitHolder(); + g_server_manager.AddUserMultiWaitHolder(dirty_event_holder); /* Loop forever, servicing our services. */ /* Because fatal has a user wait holder, we need to specify how to process manually. */ @@ -227,7 +227,7 @@ if (signaled_holder == dirty_event_holder) { /* Dirty event holder was signaled. */ fatal::srv::OnFatalDirtyEvent(); - g_server_manager.AddUserWaitableHolder(signaled_holder); + g_server_manager.AddUserMultiWaitHolder(signaled_holder); } else { /* A server/session was signaled. Have the manager handle it. */ R_ABORT_UNLESS(g_server_manager.Process(signaled_holder)); diff --git a/stratosphere/pm/source/impl/pm_process_info.cpp b/stratosphere/pm/source/impl/pm_process_info.cpp index a8252ea..bdf6418 100644 --- a/stratosphere/pm/source/impl/pm_process_info.cpp +++ b/stratosphere/pm/source/impl/pm_process_info.cpp @@ -19,8 +19,8 @@ namespace ams::pm::impl { ProcessInfo::ProcessInfo(Handle h, os::ProcessId pid, ldr::PinId pin, const ncm::ProgramLocation &l, const cfg::OverrideStatus &s) : process_id(pid), pin_id(pin), loc(l), status(s), handle(h), state(svc::ProcessState_Created), flags(0) { - os::InitializeWaitableHolder(std::addressof(this->waitable_holder), this->handle); - os::SetWaitableHolderUserData(std::addressof(this->waitable_holder), reinterpret_cast(this)); + os::InitializeMultiWaitHolder(std::addressof(this->multi_wait_holder), this->handle); + os::SetMultiWaitHolderUserData(std::addressof(this->multi_wait_holder), reinterpret_cast(this)); } ProcessInfo::~ProcessInfo() { @@ -38,8 +38,8 @@ svcCloseHandle(this->handle); this->handle = INVALID_HANDLE; - /* Unlink the process from its waitable manager. */ - os::UnlinkWaitableHolder(std::addressof(this->waitable_holder)); + /* Unlink the process from its multi wait. */ + os::UnlinkMultiWaitHolder(std::addressof(this->multi_wait_holder)); } } diff --git a/stratosphere/pm/source/impl/pm_process_info.hpp b/stratosphere/pm/source/impl/pm_process_info.hpp index 5c3d536..1315f4c 100644 --- a/stratosphere/pm/source/impl/pm_process_info.hpp +++ b/stratosphere/pm/source/impl/pm_process_info.hpp @@ -46,7 +46,7 @@ Handle handle; svc::ProcessState state; u32 flags; - os::WaitableHolderType waitable_holder; + os::MultiWaitHolderType multi_wait_holder; private: void SetFlag(Flag flag) { this->flags |= flag; @@ -64,8 +64,8 @@ ~ProcessInfo(); void Cleanup(); - void LinkToWaitableManager(os::WaitableManagerType &manager) { - os::LinkWaitableHolder(std::addressof(manager), std::addressof(this->waitable_holder)); + void LinkToMultiWait(os::MultiWaitType &multi_wait) { + os::LinkMultiWaitHolder(std::addressof(multi_wait), std::addressof(this->multi_wait_holder)); } Handle GetHandle() const { diff --git a/stratosphere/pm/source/impl/pm_process_manager.cpp b/stratosphere/pm/source/impl/pm_process_manager.cpp index 5b0a05a..49256d0 100644 --- a/stratosphere/pm/source/impl/pm_process_manager.cpp +++ b/stratosphere/pm/source/impl/pm_process_manager.cpp @@ -150,33 +150,33 @@ constinit std::atomic g_application_hook; /* Forward declarations. */ - Result LaunchProcess(os::WaitableManagerType &waitable_manager, const LaunchProcessArgs &args); + Result LaunchProcess(os::MultiWaitType &multi_wait, const LaunchProcessArgs &args); void OnProcessSignaled(ProcessListAccessor &list, ProcessInfo *process_info); /* Helpers. */ void ProcessTrackingMain(void *arg) { /* This is the main loop of the process tracking thread. */ - /* Setup waitable manager. */ - os::WaitableManagerType process_waitable_manager; - os::WaitableHolderType start_event_holder; - os::InitializeWaitableManager(std::addressof(process_waitable_manager)); - os::InitializeWaitableHolder(std::addressof(start_event_holder), g_process_launch_start_event.GetBase()); - os::LinkWaitableHolder(std::addressof(process_waitable_manager), std::addressof(start_event_holder)); + /* Setup multi wait/holders. */ + os::MultiWaitType process_multi_wait; + os::MultiWaitHolderType start_event_holder; + os::InitializeMultiWait(std::addressof(process_multi_wait)); + os::InitializeMultiWaitHolder(std::addressof(start_event_holder), g_process_launch_start_event.GetBase()); + os::LinkMultiWaitHolder(std::addressof(process_multi_wait), std::addressof(start_event_holder)); while (true) { - auto signaled_holder = os::WaitAny(std::addressof(process_waitable_manager)); + auto signaled_holder = os::WaitAny(std::addressof(process_multi_wait)); if (signaled_holder == &start_event_holder) { /* Launch start event signaled. */ /* TryWait will clear signaled, preventing duplicate notifications. */ if (g_process_launch_start_event.TryWait()) { - g_process_launch_result = LaunchProcess(process_waitable_manager, g_process_launch_args); + g_process_launch_result = LaunchProcess(process_multi_wait, g_process_launch_args); g_process_launch_finish_event.Signal(); } } else { /* Some process was signaled. */ ProcessListAccessor list(g_process_list); - OnProcessSignaled(list, reinterpret_cast(os::GetWaitableHolderUserData(signaled_holder))); + OnProcessSignaled(list, reinterpret_cast(os::GetMultiWaitHolderUserData(signaled_holder))); } } } @@ -220,7 +220,7 @@ g_process_info_allocator.FreeProcessInfo(process_info); } - Result LaunchProcess(os::WaitableManagerType &waitable_manager, const LaunchProcessArgs &args) { + Result LaunchProcess(os::MultiWaitType &multi_wait, const LaunchProcessArgs &args) { /* Get Program Info. */ ldr::ProgramInfo program_info; cfg::OverrideStatus override_status; @@ -260,7 +260,7 @@ { ProcessListAccessor list(g_process_list); list->push_back(*process_info); - process_info->LinkToWaitableManager(waitable_manager); + process_info->LinkToMultiWait(multi_wait); } /* Prevent resource leakage if register fails. */ @@ -362,7 +362,7 @@ process_info->ClearUnhandledException(); break; case svc::ProcessState_Terminated: - /* Free process resources, unlink from waitable manager. */ + /* Free process resources, unlink from multi wait. */ process_info->Cleanup(); if (hos::GetVersion() < hos::Version_5_0_0 && process_info->ShouldSignalOnExit()) { diff --git a/stratosphere/sm/source/sm_tipc_server.cpp b/stratosphere/sm/source/sm_tipc_server.cpp index 9dc4dc8..447eb85 100644 --- a/stratosphere/sm/source/sm_tipc_server.cpp +++ b/stratosphere/sm/source/sm_tipc_server.cpp @@ -47,7 +47,7 @@ private: struct Entry { sm::ServiceName service_name{sm::InvalidServiceName}; - tipc::WaitableObject object{}; + tipc::ObjectHolder object{}; u8 message_buffer[svc::ipc::MessageBufferSize]; }; private: @@ -83,7 +83,7 @@ return tipc::ResultRequestDeferred(); } - void ProcessRegisterRetry(tipc::WaitableObject &object) { + void ProcessRegisterRetry(tipc::ObjectHolder &object) { /* Verify that we have a processing entry. */ AMS_ABORT_UNLESS(m_processing_entry != nullptr);