diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 391019f87..02a8d60ba 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -18,12 +18,45 @@ #include #include #include +#include namespace ams::kern { class KThread final : public KAutoObjectWithSlabHeapAndContainer { MESOSPHERE_AUTOOBJECT_TRAITS(KThread, KSynchronizationObject); public: + enum ThreadType : u32 { + ThreadType_Main = 0, + ThreadType_Kernel = 1, + ThreadType_HighPriority = 2, + ThreadType_User = 3, + }; + + enum SuspendType : u32 { + SuspendType_Process = 0, + SuspendType_Thread = 1, + SuspendType_Debug = 2, + }; + + enum ThreadState : u16 { + ThreadState_Initialized = 0, + ThreadState_Waiting = 1, + ThreadState_Runnable = 2, + ThreadState_Terminated = 3, + + ThreadState_SuspendShift = 4, + ThreadState_Mask = (1 << ThreadState_SuspendShift) - 1, + + ThreadState_ProcessSuspended = (1 << (SuspendType_Process + ThreadState_SuspendShift)), + ThreadState_ThreadSuspended = (1 << (SuspendType_Thread + ThreadState_SuspendShift)), + ThreadState_DebugSuspended = (1 << (SuspendType_Debug + ThreadState_SuspendShift)), + }; + + enum DpcFlag : u32 { + DpcFlag_Terminating = 0, + DpcFlag_Terminated = 1, + }; + struct StackParameters { alignas(0x10) u8 svc_permission[0x10]; std::atomic dpc_flags; @@ -49,37 +82,136 @@ namespace ams::kern { constexpr ALWAYS_INLINE void SetNext(KThread *t) { this->next = t; } }; private: - /* TODO: Other members. These are placeholder to get KScheduler to compile. */ - KAffinityMask affinity_mask; - public: - constexpr KThread() : KAutoObjectWithSlabHeapAndContainer(), affinity_mask() { /* ... */ } + static constexpr size_t PriorityInheritanceCountMax = 10; + union SyncObjectBuffer { + KSynchronizationObject *sync_objects[ams::svc::MaxWaitSynchronizationHandleCount]; + ams::svc::Handle handles[ams::svc::MaxWaitSynchronizationHandleCount * (sizeof(KSynchronizationObject *) / sizeof(ams::svc::Handle))]; - constexpr ALWAYS_INLINE const KAffinityMask &GetAffinityMask() const { return this->affinity_mask; } + constexpr SyncObjectBuffer() : sync_objects() { /* ... */ } + }; + static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles)); + private: + alignas(16) KThreadContext thread_context; + KAffinityMask affinity_mask; + u64 thread_id; + std::atomic cpu_time; + KSynchronizationObject *synced_object; + KLightLock *waiting_lock; + uintptr_t condvar_key; + uintptr_t entrypoint; + KProcessAddress arbiter_key; + KProcess *parent; + void *kernel_stack_top; + u32 *light_ipc_data; + KProcessAddress tls_address; + void *tls_heap_address; + KLightLock activity_pause_lock; + SyncObjectBuffer sync_object_buffer; + s64 schedule_count; + s64 last_scheduled_tick; + QueueEntry per_core_priority_queue_entry[cpu::NumCores]; + QueueEntry sleeping_queue_entry; + void /* TODO KThreadQueue */ *sleeping_queue; + util::IntrusiveListNode waiter_list_node; + util::IntrusiveRedBlackTreeNode condvar_arbiter_tree_node; + util::IntrusiveListNode process_list_node; + + using WaiterListTraits = util::IntrusiveListMemberTraitsDeferredAssert<&KThread::waiter_list_node>; + using WaiterList = WaiterListTraits::ListType; + + WaiterList waiter_list; + WaiterList paused_waiter_list; + KThread *lock_owner; + void /* TODO KCondVar*/ *cond_var_tree; + uintptr_t debug_params[3]; + u32 arbiter_value; + u32 suspend_request_flags; + u32 suspend_allowed_flags; + Result wait_result; + Result debug_exception_result; + s32 priority; + s32 core_id; + s32 base_priority; + s32 ideal_core_id; + s32 num_kernel_waiters; + KAffinityMask original_affinity_mask; + s32 original_ideal_core_id; + s32 num_core_migration_disables; + ThreadState thread_state; + std::atomic termination_requested; + bool ipc_cancelled; + bool wait_cancelled; + bool cancelable; + bool registered; + bool signaled; + bool initialized; + bool debug_attached; + s8 priority_inheritance_count; + bool resource_limit_release_hint; public: static void PostDestroy(uintptr_t arg); + public: + explicit KThread() /* TODO: : ? */ { MESOSPHERE_ASSERT_THIS(); } + /* TODO: Is a constexpr KThread() possible? */ + private: + StackParameters &GetStackParameters() { + return *(reinterpret_cast(this->kernel_stack_top) - 1); + } + + const StackParameters &GetStackParameters() const { + return *(reinterpret_cast(this->kernel_stack_top) - 1); + } + public: + ALWAYS_INLINE s32 GetDisableDispatchCount() const { + MESOSPHERE_ASSERT_THIS(); + return GetStackParameters().disable_count; + } + + ALWAYS_INLINE void DisableDispatch() { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() >= 0); + GetStackParameters().disable_count++; + } + + ALWAYS_INLINE void EnableDispatch() { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(GetCurrentThread().GetDisableDispatchCount() > 0); + GetStackParameters().disable_count--; + } + + public: + constexpr ALWAYS_INLINE const KAffinityMask &GetAffinityMask() const { return this->affinity_mask; } + + /* TODO: This is a placeholder definition. */ + public: + static constexpr bool IsWaiterListValid() { + return WaiterListTraits::IsValid(); + } }; + static_assert(alignof(KThread) == 0x10); + static_assert(KThread::IsWaiterListValid()); class KScopedDisableDispatch { public: explicit ALWAYS_INLINE KScopedDisableDispatch() { - /* TODO */ + GetCurrentThread().DisableDispatch(); } ALWAYS_INLINE ~KScopedDisableDispatch() { - /* TODO */ + GetCurrentThread().EnableDispatch(); } }; class KScopedEnableDispatch { public: explicit ALWAYS_INLINE KScopedEnableDispatch() { - /* TODO */ + GetCurrentThread().EnableDispatch(); } ALWAYS_INLINE ~KScopedEnableDispatch() { - /* TODO */ + GetCurrentThread().DisableDispatch(); } }; diff --git a/libraries/libvapours/include/vapours/svc/svc_common.hpp b/libraries/libvapours/include/vapours/svc/svc_common.hpp index 938490191..659bfc261 100644 --- a/libraries/libvapours/include/vapours/svc/svc_common.hpp +++ b/libraries/libvapours/include/vapours/svc/svc_common.hpp @@ -28,6 +28,8 @@ namespace ams::svc { #error "Unknown target for svc::Handle" #endif + static constexpr size_t MaxWaitSynchronizationHandleCount = 0x40; + enum class PseudoHandle : Handle { CurrentThread = 0xFFFF8000, CurrentProcess = 0xFFFF8001, diff --git a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp index 3a88f6f03..c7d52e7c5 100644 --- a/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp +++ b/libraries/libvapours/include/vapours/util/util_intrusive_list.hpp @@ -566,6 +566,38 @@ namespace ams::util { static_assert(std::addressof(GetParent(GetNode(GetReference(DerivedStorage)))) == GetPointer(DerivedStorage)); }; + template> + class IntrusiveListMemberTraitsDeferredAssert; + + template + class IntrusiveListMemberTraitsDeferredAssert { + public: + using ListType = IntrusiveList; + + static constexpr bool IsValid() { + TYPED_STORAGE(Derived) DerivedStorage = {}; + return std::addressof(GetParent(GetNode(GetReference(DerivedStorage)))) == GetPointer(DerivedStorage); + } + private: + friend class IntrusiveList; + + static constexpr IntrusiveListNode &GetNode(Derived &parent) { + return parent.*Member; + } + + static constexpr IntrusiveListNode const &GetNode(Derived const &parent) { + return parent.*Member; + } + + static constexpr Derived &GetParent(IntrusiveListNode &node) { + return util::GetParentReference(&node); + } + + static constexpr Derived const &GetParent(IntrusiveListNode const &node) { + return util::GetParentReference(&node); + } + }; + template class IntrusiveListBaseNode : public IntrusiveListNode{}; diff --git a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp index 7f7445d30..df2e0c57c 100644 --- a/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp +++ b/libraries/libvapours/include/vapours/util/util_parent_of_member.hpp @@ -26,13 +26,15 @@ namespace ams::util { struct OffsetOfUnionHolder { template union UnionImpl { - using PaddingMember = std::array; + using PaddingMember = char; static constexpr size_t GetOffset() { return Offset; } + #pragma pack(push, 1) struct { PaddingMember padding[Offset]; MemberType members[(sizeof(ParentType) / sizeof(MemberType)) + 1]; } data; + #pragma pack(pop) UnionImpl next_union; }; @@ -47,12 +49,12 @@ namespace ams::util { }; template - union UnionImpl { /* Empty */ }; + union UnionImpl { /* Empty ... */ }; }; template struct OffsetOfCalculator { - using UnionHolder = typename OffsetOfUnionHolder::template UnionImpl; + using UnionHolder = typename OffsetOfUnionHolder::template UnionImpl; union Union { char c; UnionHolder first_union; @@ -81,15 +83,19 @@ namespace ams::util { const auto start = std::addressof(cur_union.data.members[0]); const auto next = GetNextAddress(start, target); + if constexpr (Offset > 0x10) { + __builtin_unreachable(); + } + if (next != target) { - if constexpr (Offset < sizeof(MemberType) / alignof(MemberType)) { + if constexpr (Offset < sizeof(MemberType) - 1) { return OffsetOfImpl(member, cur_union.next_union); } else { - std::abort(); + __builtin_unreachable(); } } - return (next - start) * sizeof(MemberType) + Offset * alignof(MemberType); + return (next - start) * sizeof(MemberType) + Offset; }