diff --git a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp index 7db14b565..9e153890e 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_k_thread.hpp @@ -390,6 +390,8 @@ namespace ams::kern { return this->wait_result; } + void WaitCancel(); + bool IsWaitCancelled() const { return this->wait_cancelled; } void ClearWaitCancelled() { this->wait_cancelled = false; } diff --git a/libraries/libmesosphere/source/kern_k_thread.cpp b/libraries/libmesosphere/source/kern_k_thread.cpp index 16e52b95b..ddb7cdbaa 100644 --- a/libraries/libmesosphere/source/kern_k_thread.cpp +++ b/libraries/libmesosphere/source/kern_k_thread.cpp @@ -439,6 +439,27 @@ namespace ams::kern { } } + void KThread::WaitCancel() { + MESOSPHERE_ASSERT_THIS(); + + KScopedSchedulerLock sl; + + /* Check if we're waiting and cancellable. */ + if (this->GetState() == ThreadState_Waiting && this->cancellable) { + if (this->sleeping_queue != nullptr) { + /* TODO: Cancel light IPC. */ + MESOSPHERE_UNIMPLEMENTED(); + } else { + this->SetSyncedObject(nullptr, svc::ResultCancelled()); + this->SetState(ThreadState_Runnable); + this->wait_cancelled = false; + } + } else { + /* Otherwise, note that we cancelled a wait. */ + this->wait_cancelled = true; + } + } + void KThread::TrySuspend() { MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT(KScheduler::IsSchedulerLockedByCurrentThread()); diff --git a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp index b75591fd1..05c651ab1 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_synchronization.cpp @@ -102,6 +102,16 @@ namespace ams::kern::svc { return ResultSuccess(); } + Result CancelSynchronization(ams::svc::Handle handle) { + /* Get the thread from its handle. */ + KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject(handle); + R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); + + /* Cancel the thread's wait. */ + thread->WaitCancel(); + return ResultSuccess(); + } + } /* ============================= 64 ABI ============================= */ @@ -119,7 +129,7 @@ namespace ams::kern::svc { } Result CancelSynchronization64(ams::svc::Handle handle) { - MESOSPHERE_PANIC("Stubbed SvcCancelSynchronization64 was called."); + return CancelSynchronization(handle); } void SynchronizePreemptionState64() { @@ -141,7 +151,7 @@ namespace ams::kern::svc { } Result CancelSynchronization64From32(ams::svc::Handle handle) { - MESOSPHERE_PANIC("Stubbed SvcCancelSynchronization64From32 was called."); + return CancelSynchronization(handle); } void SynchronizePreemptionState64From32() {