diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp index a7aafc24a..53ba20db0 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_process.hpp @@ -158,6 +158,10 @@ namespace ams::kern { return this->is_suspended; } + constexpr void SetSuspended(bool suspended) { + this->is_suspended = suspended; + } + Result Terminate(); constexpr bool IsTerminated() const { @@ -257,6 +261,8 @@ namespace ams::kern { Result Reset(); + Result SetActivity(ams::svc::ProcessActivity activity); + void SetPreemptionState(); Result SignalToAddress(KProcessAddress address) { diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index cfb4ca922..01e9c7934 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -433,11 +433,14 @@ namespace ams::kern { constexpr u32 GetSuspendFlags() const { return this->suspend_allowed_flags & this->suspend_request_flags; } constexpr bool IsSuspended() const { return this->GetSuspendFlags() != 0; } + constexpr bool IsSuspendRequested(SuspendType type) const { return (this->suspend_request_flags & (1u << (ThreadState_SuspendShift + type))) != 0; } void RequestSuspend(SuspendType type); void Resume(SuspendType type); void TrySuspend(); void Continue(); + Result SetActivity(ams::svc::ThreadActivity activity); + void ContinueIfHasKernelWaiters() { if (this->GetNumKernelWaiters() > 0) { this->Continue(); diff --git a/libraries/libmesosphere/source/kern_k_process.cpp b/libraries/libmesosphere/source/kern_k_process.cpp index c377bdc61..bd1f33eef 100644 --- a/libraries/libmesosphere/source/kern_k_process.cpp +++ b/libraries/libmesosphere/source/kern_k_process.cpp @@ -879,6 +879,48 @@ namespace ams::kern { return ResultSuccess(); } + Result KProcess::SetActivity(ams::svc::ProcessActivity activity) { + /* Lock ourselves and the scheduler. */ + KScopedLightLock lk(this->state_lock); + KScopedLightLock list_lk(this->list_lock); + KScopedSchedulerLock sl; + + /* Validate our state. */ + R_UNLESS(this->state != State_Terminating, svc::ResultInvalidState()); + R_UNLESS(this->state != State_Terminated, svc::ResultInvalidState()); + + /* Either pause or resume. */ + if (activity == ams::svc::ProcessActivity_Paused) { + /* Verify that we're not suspended. */ + R_UNLESS(!this->is_suspended, svc::ResultInvalidState()); + + /* Suspend all threads. */ + auto end = this->GetThreadList().end(); + for (auto it = this->GetThreadList().begin(); it != end; ++it) { + it->RequestSuspend(KThread::SuspendType_Process); + } + + /* Set ourselves as suspended. */ + this->SetSuspended(true); + } else { + MESOSPHERE_ASSERT(activity == ams::svc::ProcessActivity_Runnable); + + /* Verify that we're suspended. */ + R_UNLESS(this->is_suspended, svc::ResultInvalidState()); + + /* Resume all threads. */ + auto end = this->GetThreadList().end(); + for (auto it = this->GetThreadList().begin(); it != end; ++it) { + it->Resume(KThread::SuspendType_Process); + } + + /* Set ourselves as resumed. */ + this->SetSuspended(false); + } + + return ResultSuccess(); + } + KProcess::State KProcess::SetDebugObject(void *debug_object) { /* Attaching should only happen to non-null objects while the scheduler is locked. */ MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 8433bda1d..4894573cc 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -450,6 +450,7 @@ namespace ams::kern { MESOSPHERE_ASSERT(this->parent != nullptr); MESOSPHERE_ASSERT(affinity_mask != 0); { + KScopedLightLock lk(this->activity_pause_lock); KScopedSchedulerLock sl; MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0); @@ -491,6 +492,8 @@ namespace ams::kern { } } + /* TODO: Paused waiter list. */ + return ResultSuccess(); } @@ -610,6 +613,38 @@ namespace ams::kern { KScheduler::OnThreadStateChanged(this, old_state); } + Result KThread::SetActivity(ams::svc::ThreadActivity activity) { + /* Lock ourselves and the scheduler. */ + KScopedLightLock lk(this->activity_pause_lock); + KScopedSchedulerLock sl; + + /* Verify our state. */ + const auto cur_state = this->GetState(); + R_UNLESS((cur_state == ThreadState_Waiting || cur_state == ThreadState_Runnable), svc::ResultInvalidState()); + + /* Either pause or resume. */ + if (activity == ams::svc::ThreadActivity_Paused) { + /* Verify that we're not suspended. */ + R_UNLESS(!this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState()); + + /* Suspend. */ + this->RequestSuspend(SuspendType_Thread); + + /* TODO: Paused waiter list. */ + MESOSPHERE_UNIMPLEMENTED(); + } else { + MESOSPHERE_ASSERT(activity == ams::svc::ThreadActivity_Runnable); + + /* Verify that we're suspended. */ + R_UNLESS(this->IsSuspendRequested(SuspendType_Thread), svc::ResultInvalidState()); + + /* Resume. */ + this->Resume(SuspendType_Thread); + } + + return ResultSuccess(); + } + void KThread::AddWaiterImpl(KThread *thread) { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_activity.cpp b/libraries/libmesosphere/source/svc/kern_svc_activity.cpp index 68a9e5e0a..fe1ba168f 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_activity.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_activity.cpp @@ -21,28 +21,81 @@ namespace ams::kern::svc { namespace { + constexpr bool IsValidThreadActivity(ams::svc::ThreadActivity thread_activity) { + switch (thread_activity) { + case ams::svc::ThreadActivity_Runnable: + case ams::svc::ThreadActivity_Paused: + return true; + default: + return false; + } + } + constexpr bool IsValidProcessActivity(ams::svc::ProcessActivity process_activity) { + switch (process_activity) { + case ams::svc::ProcessActivity_Runnable: + case ams::svc::ProcessActivity_Paused: + return true; + default: + return false; + } + } + + Result SetThreadActivity(ams::svc::Handle thread_handle, ams::svc::ThreadActivity thread_activity) { + /* Validate the activity. */ + R_UNLESS(IsValidThreadActivity(thread_activity), svc::ResultInvalidEnumValue()); + + /* Get the thread from its handle. */ + KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject(thread_handle); + R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); + + /* Check that the activity is being set on a non-current thread for the current process. */ + R_UNLESS(thread->GetOwnerProcess() == GetCurrentProcessPointer(), svc::ResultInvalidHandle()); + R_UNLESS(thread.GetPointerUnsafe() != GetCurrentThreadPointer(), svc::ResultBusy()); + + /* Set the activity. */ + R_TRY(thread->SetActivity(thread_activity)); + + return ResultSuccess(); + } + + Result SetProcessActivity(ams::svc::Handle process_handle, ams::svc::ProcessActivity process_activity) { + /* Validate the activity. */ + R_UNLESS(IsValidProcessActivity(process_activity), svc::ResultInvalidEnumValue()); + + /* Get the process from its handle. */ + KScopedAutoObject process = GetCurrentProcess().GetHandleTable().GetObject(process_handle); + R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle()); + + /* Check that the activity isn't being set on the current process. */ + R_UNLESS(process.GetPointerUnsafe() != GetCurrentProcessPointer(), svc::ResultBusy()); + + /* Set the activity. */ + R_TRY(process->SetActivity(process_activity)); + + return ResultSuccess(); + } } /* ============================= 64 ABI ============================= */ Result SetThreadActivity64(ams::svc::Handle thread_handle, ams::svc::ThreadActivity thread_activity) { - MESOSPHERE_PANIC("Stubbed SvcSetThreadActivity64 was called."); + return SetThreadActivity(thread_handle, thread_activity); } Result SetProcessActivity64(ams::svc::Handle process_handle, ams::svc::ProcessActivity process_activity) { - MESOSPHERE_PANIC("Stubbed SvcSetProcessActivity64 was called."); + return SetProcessActivity(process_handle, process_activity); } /* ============================= 64From32 ABI ============================= */ Result SetThreadActivity64From32(ams::svc::Handle thread_handle, ams::svc::ThreadActivity thread_activity) { - MESOSPHERE_PANIC("Stubbed SvcSetThreadActivity64From32 was called."); + return SetThreadActivity(thread_handle, thread_activity); } Result SetProcessActivity64From32(ams::svc::Handle process_handle, ams::svc::ProcessActivity process_activity) { - MESOSPHERE_PANIC("Stubbed SvcSetProcessActivity64From32 was called."); + return SetProcessActivity(process_handle, process_activity); } } diff --git a/libraries/libmesosphere/source/svc/kern_svc_processor.cpp b/libraries/libmesosphere/source/svc/kern_svc_processor.cpp index c89185f51..61e25b72b 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_processor.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_processor.cpp @@ -21,20 +21,22 @@ namespace ams::kern::svc { namespace { - + int32_t GetCurrentProcessorNumber() { + return GetCurrentCoreId(); + } } /* ============================= 64 ABI ============================= */ int32_t GetCurrentProcessorNumber64() { - MESOSPHERE_PANIC("Stubbed SvcGetCurrentProcessorNumber64 was called."); + return GetCurrentProcessorNumber(); } /* ============================= 64From32 ABI ============================= */ int32_t GetCurrentProcessorNumber64From32() { - MESOSPHERE_PANIC("Stubbed SvcGetCurrentProcessorNumber64From32 was called."); + return GetCurrentProcessorNumber(); } }