From 6643673f28b9273149fc945849a13ed832e9ef33 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sun, 18 Jan 2015 01:27:46 -0500 Subject: WaitSynchronizationN: Refactor to fix several bugs - Separate wait checking from waiting the current thread - Resume thread when wait_all=true only if all objects are available at once - Set output to correct wait object index when there are duplicate handles --- src/core/hle/kernel/thread.cpp | 61 +++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 33 deletions(-) (limited to 'src/core/hle/kernel/thread.cpp') diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6b0bdebb..62b85f56 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -22,11 +22,11 @@ namespace Kernel { -ResultVal Thread::Wait(unsigned index) { +ResultVal Thread::Wait(bool wait_thread) { const bool wait = status != THREADSTATUS_DORMANT; - if (wait) { + if (wait && wait_thread) { AddWaitingThread(GetCurrentThread()); - WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); + WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this); } return MakeResult(wait); @@ -97,7 +97,7 @@ static bool CheckWaitType(const Thread* thread, WaitType type) { /// Check if a thread is blocking on a specified wait type with a specified handle static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { - if (itr->first == wait_object) + if (*itr == wait_object) return CheckWaitType(thread, type); } return false; @@ -234,16 +234,7 @@ void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_ Thread* thread = GetCurrentThread(); thread->wait_type = wait_type; - bool insert_wait_object = true; - for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) { - if (itr->first == wait_object) { - insert_wait_object = false; - break; - } - } - - if (insert_wait_object) - thread->wait_objects.push_back(std::pair, unsigned>(wait_object, index)); + thread->wait_objects.push_back(wait_object); ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); } @@ -288,31 +279,35 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) { return; } - // Remove this thread from the wait_object + // Remove this thread from the waiting object's thread list wait_object->RemoveWaitingThread(this); - // Find the waiting object - auto itr = wait_objects.begin(); - for (; itr != wait_objects.end(); ++itr) { - if (wait_object == itr->first) - break; - } - unsigned index = itr->second; + unsigned index = 0; + bool wait_all_failed = false; // Will be set to true if any object is unavailable - // Remove the wait_object from this thread - if (itr != wait_objects.end()) - wait_objects.erase(itr); + // Iterate through all waiting objects to check availability... + for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { + auto res = (*itr)->Wait(false); - // If wait_all=false, resume the thread on a release wait_object from wait - if (!wait_all) { - SetReturnValue(RESULT_SUCCESS, index); - ResumeFromWait(); - } else { - // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released - if (wait_objects.empty()) { + if (*res && res.Succeeded()) + wait_all_failed = true; + + // The output should be the last index of wait_object + if (*itr == wait_object) + index = itr - wait_objects.begin(); + } + + // If we are waiting on all objects... + if (wait_all) { + // Resume the thread only if all are available... + if (!wait_all_failed) { SetReturnValue(RESULT_SUCCESS, -1); ResumeFromWait(); } + } else { + // Otherwise, resume + SetReturnValue(RESULT_SUCCESS, index); + ResumeFromWait(); } } @@ -324,7 +319,7 @@ void Thread::ResumeFromWait() { // Remove this thread from all other WaitObjects for (auto wait_object : wait_objects) - wait_object.first->RemoveWaitingThread(this); + wait_object->RemoveWaitingThread(this); wait_objects.clear(); -- cgit v1.2.3