From 4a767c908231a4c4f4f6b7cbfc6f9c16f4fba3be Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Fri, 10 Jul 2020 18:39:53 -0700 Subject: [PATCH] kern: mostly implement thread exit --- .../include/mesosphere/kern_k_process.hpp | 12 +++ .../include/mesosphere/kern_k_scheduler.hpp | 2 + .../include/mesosphere/kern_k_thread.hpp | 3 + .../include/mesosphere/kern_kernel.hpp | 4 + .../source/kern_k_page_table_base.cpp | 2 +- .../libmesosphere/source/kern_k_process.cpp | 19 +++++ .../libmesosphere/source/kern_k_scheduler.cpp | 10 +++ .../libmesosphere/source/kern_k_thread.cpp | 77 ++++++++++++++++++- 8 files changed, 126 insertions(+), 3 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 02100f8ef..fc3ff15bb 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -147,6 +147,10 @@ namespace ams::kern { return this->is_suspended; } + bool EnterUserException(); + bool LeaveUserException(); + bool ReleaseUserException(KThread *thread); + KThread *GetPreemptionStatePinnedThread(s32 core_id) const { MESOSPHERE_ASSERT(0 <= core_id && core_id < static_cast(cpu::NumCores)); return this->pinned_threads[core_id]; @@ -186,6 +190,14 @@ namespace ams::kern { void IncrementThreadCount(); void DecrementThreadCount(); + void ClearRunningThread(KThread *thread) { + for (size_t i = 0; i < util::size(this->running_threads); ++i) { + if (this->running_threads[i] == thread) { + this->running_threads[i] = nullptr; + } + } + } + void RegisterThread(KThread *thread); void UnregisterThread(KThread *thread); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp index 2e8247f5a..ba834a8b8 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp @@ -116,6 +116,8 @@ namespace ams::kern { } } + static NOINLINE void ClearPreviousThread(KThread *thread); + static NOINLINE void OnThreadStateChanged(KThread *thread, KThread::ThreadState old_state); static NOINLINE void OnThreadPriorityChanged(KThread *thread, s32 old_priority); static NOINLINE void OnThreadAffinityMaskChanged(KThread *thread, const KAffinityMask &old_affinity, s32 old_core); diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 462d25ddb..5c7febd1a 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -268,6 +268,9 @@ namespace ams::kern { ALWAYS_INLINE void AddWaiterImpl(KThread *thread); ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread); ALWAYS_INLINE static void RestorePriority(KThread *thread); + + void StartTermination(); + void FinishTermination(); public: constexpr u64 GetThreadId() const { return this->thread_id; } diff --git a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp index 4d4845240..21980a083 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_kernel.hpp @@ -94,6 +94,10 @@ namespace ams::kern { static KThread &GetMainThread(s32 core_id); static KThread &GetIdleThread(s32 core_id); + static ALWAYS_INLINE KCurrentContext &GetCurrentContext(s32 core_id) { + return GetCoreLocalContext(core_id).current; + } + static ALWAYS_INLINE KScheduler &GetScheduler() { return GetCoreLocalContext().scheduler; } diff --git a/libraries/libmesosphere/source/kern_k_page_table_base.cpp b/libraries/libmesosphere/source/kern_k_page_table_base.cpp index 15ed08e25..92c5f9eac 100644 --- a/libraries/libmesosphere/source/kern_k_page_table_base.cpp +++ b/libraries/libmesosphere/source/kern_k_page_table_base.cpp @@ -613,7 +613,7 @@ namespace ams::kern { /* Apply the memory block updates. */ this->memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, new_src_perm, new_src_attr); - this->memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryAttribute_None); + this->memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_Stack, KMemoryPermission_UserReadWrite, KMemoryAttribute_None); } return ResultSuccess(); diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index 842fe1a2e..6a9d246e2 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -272,6 +272,25 @@ namespace ams::kern { } } + bool KProcess::EnterUserException() { + MESOSPHERE_UNIMPLEMENTED(); + } + + bool KProcess::LeaveUserException() { + return this->ReleaseUserException(GetCurrentThreadPointer()); + } + + bool KProcess::ReleaseUserException(KThread *thread) { + KScopedSchedulerLock sl; + + if (this->exception_thread == thread) { + /* TODO */ + MESOSPHERE_UNIMPLEMENTED(); + } else { + return false; + } + } + void KProcess::RegisterThread(KThread *thread) { KScopedLightLock lk(this->list_lock); diff --git a/libraries/libmesosphere/source/kern_k_scheduler.cpp b/libraries/libmesosphere/source/kern_k_scheduler.cpp index 97dcb1165..6208b8ab0 100644 --- a/libraries/libmesosphere/source/kern_k_scheduler.cpp +++ b/libraries/libmesosphere/source/kern_k_scheduler.cpp @@ -262,6 +262,16 @@ namespace ams::kern { cpu::SwitchThreadLocalRegion(GetInteger(next_thread->GetThreadLocalRegionAddress())); } + void KScheduler::ClearPreviousThread(KThread *thread) { + MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); + for (size_t i = 0; i < cpu::NumCores; ++i) { + std::atomic *prev_thread_ptr = reinterpret_cast *>(std::addressof(Kernel::GetScheduler(static_cast(i)).prev_thread)); + static_assert(sizeof(*prev_thread_ptr) == sizeof(KThread *)); + + prev_thread_ptr->compare_exchange_weak(thread, nullptr); + } + } + void KScheduler::OnThreadStateChanged(KThread *thread, KThread::ThreadState old_state) { MESOSPHERE_ASSERT(IsSchedulerLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 2fb52b283..cc0ed73b4 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -278,8 +278,60 @@ namespace ams::kern { this->Wakeup(); } + void KThread::StartTermination() { + MESOSPHERE_ASSERT_THIS(); + MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); + + /* Release user exception, if relevant. */ + if (this->parent != nullptr) { + this->parent->ReleaseUserException(this); + if (this->parent->GetPreemptionStatePinnedThread(GetCurrentCoreId()) == this) { + /* TODO: this->parent->UnpinCurrentThread(); */ + MESOSPHERE_UNIMPLEMENTED(); + } + } + + /* Set state to terminated. */ + this->SetState(KThread::ThreadState_Terminated); + + /* Clear the thread's status as running in parent. */ + if (this->parent != nullptr) { + this->parent->ClearRunningThread(this); + } + + /* Signal. */ + this->signaled = true; + this->NotifyAvailable(); + + /* TODO: On Thread Termination handler */ + + /* Clear previous thread in KScheduler. */ + KScheduler::ClearPreviousThread(this); + + /* Register terminated dpc flag. */ + this->RegisterDpc(DpcFlag_Terminated); + } + + void KThread::FinishTermination() { + MESOSPHERE_ASSERT_THIS(); + + /* Ensure that the thread is not executing on any core. */ + if (this->parent != nullptr) { + for (size_t i = 0; i < cpu::NumCores; ++i) { + KThread *core_thread; + do { + core_thread = Kernel::GetCurrentContext(i).current_thread.load(std::memory_order_acquire); + } while (core_thread == this); + } + } + + /* Close the thread. */ + this->Close(); + } + void KThread::DoWorkerTask() { - MESOSPHERE_UNIMPLEMENTED(); + /* Finish the termination that was begun by Exit(). */ + this->FinishTermination(); } void KThread::DisableCoreMigration() { @@ -586,7 +638,28 @@ namespace ams::kern { void KThread::Exit() { MESOSPHERE_ASSERT_THIS(); - MESOSPHERE_UNIMPLEMENTED(); + MESOSPHERE_ASSERT(this == GetCurrentThreadPointer()); + + /* TODO: KDebug::OnExitThread(this); */ + + /* Release the thread resource hint from parent. */ + if (this->parent != nullptr) { + this->parent->ReleaseResource(ams::svc::LimitableResource_ThreadCountMax, 0, 1); + } + + /* Perform termination. */ + { + KScopedSchedulerLock sl; + + /* Disallow all suspension. */ + this->suspend_allowed_flags = 0; + + /* Start termination. */ + this->StartTermination(); + + /* Register the thread as a work task. */ + KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_Exit, this); + } MESOSPHERE_PANIC("KThread::Exit() would return"); }