From 2a3f8e8484fca54767c9874cc21f5985d2be1463 Mon Sep 17 00:00:00 2001 From: Subv Date: Mon, 8 Jan 2018 11:35:03 -0500 Subject: Kernel: Allow chaining WaitSynchronization calls inside a wakeup callback. --- src/core/hle/kernel/svc.cpp | 56 +++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'src/core/hle/kernel/svc.cpp') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 74643f598..73793955a 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -120,17 +120,19 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { } /// Default thread wakeup callback for WaitSynchronization -static void DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr thread, - SharedPtr object) { +static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, SharedPtr thread, + SharedPtr object, size_t index) { ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY); if (reason == ThreadWakeupReason::Timeout) { thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return; + return true; } ASSERT(reason == ThreadWakeupReason::Signal); thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + + return true; }; /// Wait for a kernel object to synchronize, timeout after the specified nanoseconds @@ -499,20 +501,44 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr semaphore_add ASSERT(semaphore->available_count == 0); ASSERT(semaphore->mutex_addr == mutex_addr); - CASCADE_CODE(WaitSynchronization1( - semaphore, thread.get(), nano_seconds, - [mutex](ThreadWakeupReason reason, SharedPtr thread, SharedPtr object) { - ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY); + auto wakeup_callback = [mutex, nano_seconds](ThreadWakeupReason reason, + SharedPtr thread, + SharedPtr object, size_t index) { + ASSERT(thread->status == THREADSTATUS_WAIT_SYNCH_ANY); + + if (reason == ThreadWakeupReason::Timeout) { + thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); + return true; + } + + ASSERT(reason == ThreadWakeupReason::Signal); + + // Now try to acquire the mutex and don't resume if it's not available. + if (!mutex->ShouldWait(thread.get())) { + mutex->Acquire(thread.get()); + thread->SetWaitSynchronizationResult(RESULT_SUCCESS); + return true; + } - if (reason == ThreadWakeupReason::Timeout) { - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); - return; - } + if (nano_seconds == 0) { + thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); + return true; + } + + thread->wait_objects = {mutex}; + mutex->AddWaitingThread(thread); + thread->status = THREADSTATUS_WAIT_SYNCH_ANY; + + // Create an event to wake the thread up after the + // specified nanosecond delay has passed + thread->WakeAfterDelay(nano_seconds); + thread->wakeup_callback = DefaultThreadWakeupCallback; + + Core::System::GetInstance().PrepareReschedule(); - ASSERT(reason == ThreadWakeupReason::Signal); - thread->SetWaitSynchronizationResult(WaitSynchronization1(mutex, thread.get())); - thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get())); - })); + return false; + }; + CASCADE_CODE(WaitSynchronization1(semaphore, thread.get(), nano_seconds, wakeup_callback)); mutex->Release(thread.get()); -- cgit v1.2.3