aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar bunnei <bunneidev@gmail.com>2015-01-18 01:27:46 -0500
committerGravatar bunnei <bunneidev@gmail.com>2015-01-21 19:11:47 -0500
commit6643673f28b9273149fc945849a13ed832e9ef33 (patch)
tree026410cf5b0b57d350ac979380307991646e546c /src/core/hle/kernel/thread.cpp
parentaa01c57ae9d73e41b65d37860ca6fbb91caba33a (diff)
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
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp61
1 files changed, 28 insertions, 33 deletions
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<bool> Thread::Wait(unsigned index) {
+ResultVal<bool> 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<bool>(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<SharedPtr<WaitObject>, 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();