From 256eb92f4cd4cb4c807b6c91652e6a659902d538 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 7 Apr 2021 08:17:15 -0700 Subject: [PATCH] kern: update process/thread for new running/termination semantics --- .../include/mesosphere/kern_k_process.hpp | 10 ++- .../include/mesosphere/kern_k_thread.hpp | 4 +- .../nintendo/nx/kern_k_device_page_table.cpp | 2 +- .../source/kern_initial_process.cpp | 1 + .../libmesosphere/source/kern_k_process.cpp | 68 +++++++++++-------- .../libmesosphere/source/kern_k_thread.cpp | 60 ++++++++-------- .../source/svc/kern_svc_process.cpp | 7 +- .../source/svc/kern_svc_thread.cpp | 6 +- 8 files changed, 76 insertions(+), 82 deletions(-) diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index 9e5dd82f7..c2d50acdf 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -77,8 +77,7 @@ namespace ams::kern { bool m_is_initialized{}; bool m_is_application{}; char m_name[13]{}; - std::atomic m_num_threads{}; - u16 m_peak_num_threads{}; + std::atomic m_num_running_threads{}; u32 m_flags{}; KMemoryManager::Pool m_memory_pool{}; s64 m_schedule_count{}; @@ -108,7 +107,6 @@ namespace ams::kern { KThread *m_running_threads[cpu::NumCores]{}; u64 m_running_thread_idle_counts[cpu::NumCores]{}; KThread *m_pinned_threads[cpu::NumCores]{}; - std::atomic m_num_created_threads{}; std::atomic m_cpu_time{}; std::atomic m_num_process_switches{}; std::atomic m_num_thread_switches{}; @@ -124,7 +122,7 @@ namespace ams::kern { private: Result Initialize(const ams::svc::CreateProcessParameter ¶ms); - void StartTermination(); + Result StartTermination(); void FinishTermination(); void PinThread(s32 core_id, KThread *thread) { @@ -285,8 +283,8 @@ namespace ams::kern { constexpr s64 GetScheduledCount() const { return m_schedule_count; } void IncrementScheduledCount() { ++m_schedule_count; } - void IncrementThreadCount(); - void DecrementThreadCount(); + void IncrementRunningThreadCount(); + void DecrementRunningThreadCount(); size_t GetTotalSystemResourceSize() const { return m_system_resource_num_pages * PageSize; } size_t GetUsedSystemResourceSize() const { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 715bd0deb..ff8dfadea 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -340,7 +340,7 @@ namespace ams::kern { return this->GetDpc() != 0; } private: - void Suspend(); + void UpdateState(); ALWAYS_INLINE void AddWaiterImpl(KThread *thread); ALWAYS_INLINE void RemoveWaiterImpl(KThread *thread); ALWAYS_INLINE static void RestorePriority(KThread *thread); @@ -535,7 +535,7 @@ namespace ams::kern { Result Run(); void Exit(); - void Terminate(); + Result Terminate(); ThreadState RequestTerminate(); Result Sleep(s64 timeout); diff --git a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp index 76410a1fc..582df3f7f 100644 --- a/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp +++ b/libraries/libmesosphere/source/board/nintendo/nx/kern_k_device_page_table.cpp @@ -526,7 +526,7 @@ namespace ams::kern::board::nintendo::nx { #if defined(MESOSPHERE_ENABLE_MEMORY_CONTROLLER_INTERRUPT) { /* Clear the interrupt when we're done. */ - ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController); }; + ON_SCOPE_EXIT { Kernel::GetInterruptManager().ClearInterrupt(KInterruptName_MemoryController, GetCurrentCoreId()); }; /* Get and clear the interrupt status. */ u32 int_status, err_status, err_adr; diff --git a/libraries/libmesosphere/source/kern_initial_process.cpp b/libraries/libmesosphere/source/kern_initial_process.cpp index 1b526ca6d..be962d668 100644 --- a/libraries/libmesosphere/source/kern_initial_process.cpp +++ b/libraries/libmesosphere/source/kern_initial_process.cpp @@ -210,6 +210,7 @@ namespace ams::kern { /* Run the processes. */ for (size_t i = 0; i < g_initial_process_binary_header.num_processes; i++) { MESOSPHERE_R_ABORT_UNLESS(infos[i].process->Run(infos[i].priority, infos[i].stack_size)); + infos[i].process->Close(); } } diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index f8a0ad354..6aaaefa8f 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -28,7 +28,7 @@ namespace ams::kern { std::atomic g_initial_process_id = InitialProcessIdMin; std::atomic g_process_id = ProcessIdMin; - void TerminateChildren(KProcess *process, const KThread *thread_to_not_terminate) { + Result TerminateChildren(KProcess *process, const KThread *thread_to_not_terminate) { /* Request that all children threads terminate. */ { KScopedLightLock proc_lk(process->GetListLock()); @@ -70,9 +70,14 @@ namespace ams::kern { } /* Terminate and close the thread. */ - cur_child->Terminate(); - cur_child->Close(); + ON_SCOPE_EXIT { cur_child->Close(); }; + + if (Result terminate_result = cur_child->Terminate(); svc::ResultTerminationRequested::Includes(terminate_result)) { + return terminate_result; + } } + + return ResultSuccess(); } } @@ -206,9 +211,7 @@ namespace ams::kern { KSystemControl::GenerateRandomBytes(m_entropy, sizeof(m_entropy)); /* Clear remaining fields. */ - m_num_threads = 0; - m_peak_num_threads = 0; - m_num_created_threads = 0; + m_num_running_threads = 0; m_num_process_switches = 0; m_num_thread_switches = 0; m_num_fpu_switches = 0; @@ -402,12 +405,14 @@ namespace ams::kern { this->FinishTermination(); } - void KProcess::StartTermination() { - /* Terminate child threads other than the current one. */ - TerminateChildren(this, GetCurrentThreadPointer()); + Result KProcess::StartTermination() { + /* Finalize the handle table, when we're done. */ + ON_SCOPE_EXIT { + m_handle_table.Finalize(); + }; - /* Finalize the handle tahble. */ - m_handle_table.Finalize(); + /* Terminate child threads other than the current one. */ + return TerminateChildren(this, GetCurrentThreadPointer()); } void KProcess::FinishTermination() { @@ -485,16 +490,22 @@ namespace ams::kern { /* If we need to terminate, do so. */ if (needs_terminate) { /* Start termination. */ - this->StartTermination(); + if (R_SUCCEEDED(this->StartTermination())) { + /* Note for debug that we're terminating the process. */ + MESOSPHERE_LOG("KProcess::Terminate() OK pid=%ld name=%-12s\n", m_process_id, m_name); - /* Note for debug that we're terminating the process. */ - MESOSPHERE_LOG("KProcess::Terminate() pid=%ld name=%-12s\n", m_process_id, m_name); + /* Call the debug callback. */ + KDebug::OnTerminateProcess(this); - /* Call the debug callback. */ - KDebug::OnTerminateProcess(this); + /* Finish termination. */ + this->FinishTermination(); + } else { + /* Note for debug that we're terminating the process. */ + MESOSPHERE_LOG("KProcess::Terminate() FAIL pid=%ld name=%-12s\n", m_process_id, m_name); - /* Finish termination. */ - this->FinishTermination(); + /* Register the process as a work task. */ + KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_Exit, this); + } } return ResultSuccess(); @@ -703,19 +714,16 @@ namespace ams::kern { } } - void KProcess::IncrementThreadCount() { - MESOSPHERE_ASSERT(m_num_threads >= 0); - ++m_num_created_threads; + void KProcess::IncrementRunningThreadCount() { + MESOSPHERE_ASSERT(m_num_running_threads.load() >= 0); - if (const auto count = ++m_num_threads; count > m_peak_num_threads) { - m_peak_num_threads = count; - } + m_num_running_threads.fetch_add(1); } - void KProcess::DecrementThreadCount() { - MESOSPHERE_ASSERT(m_num_threads > 0); + void KProcess::DecrementRunningThreadCount() { + MESOSPHERE_ASSERT(m_num_running_threads.load() > 0); - if (const auto count = --m_num_threads; count == 0) { + if (m_num_running_threads.fetch_sub(1) == 1) { this->Terminate(); } } @@ -896,7 +904,7 @@ namespace ams::kern { /* Create a new thread for the process. */ KThread *main_thread = KThread::Create(); R_UNLESS(main_thread != nullptr, svc::ResultOutOfResource()); - auto thread_guard = SCOPE_GUARD { main_thread->Close(); }; + ON_SCOPE_EXIT { main_thread->Close(); }; /* Initialize the thread. */ R_TRY(KThread::InitializeUserThread(main_thread, reinterpret_cast(GetVoidPointer(this->GetEntryPoint())), 0, stack_top, priority, m_ideal_core_id, this)); @@ -919,9 +927,11 @@ namespace ams::kern { /* Run our thread. */ R_TRY(main_thread->Run()); + /* Open a reference to represent that we're running. */ + this->Open(); + /* We succeeded! Cancel our guards. */ state_guard.Cancel(); - thread_guard.Cancel(); ht_guard.Cancel(); stack_guard.Cancel(); mem_reservation.Commit(); diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index c25b9b121..972e4220d 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -184,7 +184,6 @@ namespace ams::kern { if (owner != nullptr) { m_parent = owner; m_parent->Open(); - m_parent->IncrementThreadCount(); } /* Initialize thread context. */ @@ -312,11 +311,6 @@ namespace ams::kern { CleanupKernelStack(reinterpret_cast(m_kernel_stack_top)); } - /* Decrement the parent process's thread count. */ - if (m_parent != nullptr) { - m_parent->DecrementThreadCount(); - } - /* Perform inherited finalization. */ KAutoObjectWithSlabHeapAndContainer::Finalize(); } @@ -444,11 +438,7 @@ namespace ams::kern { m_suspend_allowed_flags &= ~(1 << (SuspendType_Thread + ThreadState_SuspendShift)); /* Update our state. */ - const ThreadState old_state = m_thread_state; - m_thread_state = static_cast(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); - if (m_thread_state != old_state) { - KScheduler::OnThreadStateChanged(this, old_state); - } + this->UpdateState(); } /* Update our SVC access permissions. */ @@ -499,11 +489,7 @@ namespace ams::kern { } /* Update our state. */ - const ThreadState old_state = m_thread_state; - m_thread_state = static_cast(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); - if (m_thread_state != old_state) { - KScheduler::OnThreadStateChanged(this, old_state); - } + this->UpdateState(); } /* Update our SVC access permissions. */ @@ -790,11 +776,7 @@ namespace ams::kern { m_suspend_request_flags &= ~(1u << (ThreadState_SuspendShift + type)); /* Update our state. */ - const ThreadState old_state = m_thread_state; - m_thread_state = static_cast(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); - if (m_thread_state != old_state) { - KScheduler::OnThreadStateChanged(this, old_state); - } + this->UpdateState(); } void KThread::WaitCancel() { @@ -830,20 +812,22 @@ namespace ams::kern { MESOSPHERE_ABORT_UNLESS(this->GetNumKernelWaiters() == 0); /* Perform the suspend. */ - this->Suspend(); + this->UpdateState(); } - void KThread::Suspend() { + void KThread::UpdateState() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); - MESOSPHERE_ASSERT(this->IsSuspendRequested()); /* Set our suspend flags in state. */ const auto old_state = m_thread_state; - m_thread_state = static_cast(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); + const auto new_state = static_cast(this->GetSuspendFlags() | (old_state & ThreadState_Mask)); + m_thread_state = new_state; /* Note the state change in scheduler. */ - KScheduler::OnThreadStateChanged(this, old_state); + if (new_state != old_state) { + KScheduler::OnThreadStateChanged(this, old_state); + } } void KThread::Continue() { @@ -1137,15 +1121,21 @@ namespace ams::kern { /* If the current thread has been asked to suspend, suspend it and retry. */ if (GetCurrentThread().IsSuspended()) { - GetCurrentThread().Suspend(); + GetCurrentThread().UpdateState(); continue; } /* If we're not a kernel thread and we've been asked to suspend, suspend ourselves. */ - if (this->IsUserThread() && this->IsSuspended()) { - this->Suspend(); + if (KProcess *parent = this->GetOwnerProcess(); parent != nullptr) { + if (this->IsSuspended()) { + this->UpdateState(); + } + parent->IncrementRunningThreadCount(); } + /* Open a reference, now that we're running. */ + this->Open(); + /* Set our state and finish. */ this->SetState(KThread::ThreadState_Runnable); return ResultSuccess(); @@ -1160,10 +1150,11 @@ namespace ams::kern { /* Call the debug callback. */ KDebug::OnExitThread(this); - /* Release the thread resource hint from parent. */ + /* Release the thread resource hint, running thread count from parent. */ if (m_parent != nullptr) { m_parent->ReleaseResource(ams::svc::LimitableResource_ThreadCountMax, 0, 1); m_resource_limit_release_hint = true; + m_parent->DecrementRunningThreadCount(); } /* Perform termination. */ @@ -1172,6 +1163,7 @@ namespace ams::kern { /* Disallow all suspension. */ m_suspend_allowed_flags = 0; + this->UpdateState(); /* Start termination. */ this->StartTermination(); @@ -1183,7 +1175,7 @@ namespace ams::kern { MESOSPHERE_PANIC("KThread::Exit() would return"); } - void KThread::Terminate() { + Result KThread::Terminate() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(this != GetCurrentThreadPointer()); @@ -1192,7 +1184,9 @@ namespace ams::kern { /* If the thread isn't terminated, wait for it to terminate. */ s32 index; KSynchronizationObject *objects[] = { this }; - KSynchronizationObject::Wait(std::addressof(index), objects, 1, ams::svc::WaitInfinite); + return KSynchronizationObject::Wait(std::addressof(index), objects, 1, ams::svc::WaitInfinite); + } else { + return ResultSuccess(); } } @@ -1223,7 +1217,7 @@ namespace ams::kern { /* If the thread is suspended, continue it. */ if (this->IsSuspended()) { m_suspend_allowed_flags = 0; - this->Continue(); + this->UpdateState(); } /* Change the thread's priority to be higher than any system thread's. */ diff --git a/libraries/libmesosphere/source/svc/kern_svc_process.cpp b/libraries/libmesosphere/source/svc/kern_svc_process.cpp index 7625cbf3b..6d12f2bfd 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_process.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_process.cpp @@ -286,12 +286,7 @@ namespace ams::kern::svc { process->SetIdealCoreId(core_id); /* Run the process. */ - R_TRY(process->Run(priority, static_cast(main_thread_stack_size))); - - /* Open a reference to the process, since it's now running. */ - process->Open(); - - return ResultSuccess(); + return process->Run(priority, static_cast(main_thread_stack_size)); } Result TerminateProcess(ams::svc::Handle process_handle) { diff --git a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp index 3c511008b..e8277a22b 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_thread.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_thread.cpp @@ -75,11 +75,7 @@ namespace ams::kern::svc { R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); /* Try to start the thread. */ - R_TRY(thread->Run()); - - /* If we succeeded, persist a reference to the thread. */ - thread->Open(); - return ResultSuccess(); + return thread->Run(); } void ExitThread() {