summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2015-01-18 01:27:46 -0500
committerGravatar bunnei2015-01-21 19:11:47 -0500
commit6643673f28b9273149fc945849a13ed832e9ef33 (patch)
tree026410cf5b0b57d350ac979380307991646e546c /src/core/hle/kernel/thread.cpp
parentKernel: Separate WaitSynchronization into Wait and Acquire methods. (diff)
downloadyuzu-6643673f28b9273149fc945849a13ed832e9ef33.tar.gz
yuzu-6643673f28b9273149fc945849a13ed832e9ef33.tar.xz
yuzu-6643673f28b9273149fc945849a13ed832e9ef33.zip
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 6b0bdebb5..62b85f56a 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -22,11 +22,11 @@
22 22
23namespace Kernel { 23namespace Kernel {
24 24
25ResultVal<bool> Thread::Wait(unsigned index) { 25ResultVal<bool> Thread::Wait(bool wait_thread) {
26 const bool wait = status != THREADSTATUS_DORMANT; 26 const bool wait = status != THREADSTATUS_DORMANT;
27 if (wait) { 27 if (wait && wait_thread) {
28 AddWaitingThread(GetCurrentThread()); 28 AddWaitingThread(GetCurrentThread());
29 WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this, index); 29 WaitCurrentThread_WaitSynchronization(WAITTYPE_THREADEND, this);
30 } 30 }
31 31
32 return MakeResult<bool>(wait); 32 return MakeResult<bool>(wait);
@@ -97,7 +97,7 @@ static bool CheckWaitType(const Thread* thread, WaitType type) {
97/// Check if a thread is blocking on a specified wait type with a specified handle 97/// Check if a thread is blocking on a specified wait type with a specified handle
98static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) { 98static bool CheckWaitType(const Thread* thread, WaitType type, Object* wait_object) {
99 for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) { 99 for (auto itr = thread->wait_objects.begin(); itr != thread->wait_objects.end(); ++itr) {
100 if (itr->first == wait_object) 100 if (*itr == wait_object)
101 return CheckWaitType(thread, type); 101 return CheckWaitType(thread, type);
102 } 102 }
103 return false; 103 return false;
@@ -234,16 +234,7 @@ void WaitCurrentThread_WaitSynchronization(WaitType wait_type, WaitObject* wait_
234 Thread* thread = GetCurrentThread(); 234 Thread* thread = GetCurrentThread();
235 thread->wait_type = wait_type; 235 thread->wait_type = wait_type;
236 236
237 bool insert_wait_object = true; 237 thread->wait_objects.push_back(wait_object);
238 for (auto itr = thread->wait_objects.begin(); itr < thread->wait_objects.end(); ++itr) {
239 if (itr->first == wait_object) {
240 insert_wait_object = false;
241 break;
242 }
243 }
244
245 if (insert_wait_object)
246 thread->wait_objects.push_back(std::pair<SharedPtr<WaitObject>, unsigned>(wait_object, index));
247 238
248 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); 239 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
249} 240}
@@ -288,31 +279,35 @@ void Thread::ReleaseFromWait(WaitObject* wait_object) {
288 return; 279 return;
289 } 280 }
290 281
291 // Remove this thread from the wait_object 282 // Remove this thread from the waiting object's thread list
292 wait_object->RemoveWaitingThread(this); 283 wait_object->RemoveWaitingThread(this);
293 284
294 // Find the waiting object 285 unsigned index = 0;
295 auto itr = wait_objects.begin(); 286 bool wait_all_failed = false; // Will be set to true if any object is unavailable
296 for (; itr != wait_objects.end(); ++itr) {
297 if (wait_object == itr->first)
298 break;
299 }
300 unsigned index = itr->second;
301 287
302 // Remove the wait_object from this thread 288 // Iterate through all waiting objects to check availability...
303 if (itr != wait_objects.end()) 289 for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) {
304 wait_objects.erase(itr); 290 auto res = (*itr)->Wait(false);
305 291
306 // If wait_all=false, resume the thread on a release wait_object from wait 292 if (*res && res.Succeeded())
307 if (!wait_all) { 293 wait_all_failed = true;
308 SetReturnValue(RESULT_SUCCESS, index); 294
309 ResumeFromWait(); 295 // The output should be the last index of wait_object
310 } else { 296 if (*itr == wait_object)
311 // Otherwise, wait_all=true, only resume the thread if all wait_object's have been released 297 index = itr - wait_objects.begin();
312 if (wait_objects.empty()) { 298 }
299
300 // If we are waiting on all objects...
301 if (wait_all) {
302 // Resume the thread only if all are available...
303 if (!wait_all_failed) {
313 SetReturnValue(RESULT_SUCCESS, -1); 304 SetReturnValue(RESULT_SUCCESS, -1);
314 ResumeFromWait(); 305 ResumeFromWait();
315 } 306 }
307 } else {
308 // Otherwise, resume
309 SetReturnValue(RESULT_SUCCESS, index);
310 ResumeFromWait();
316 } 311 }
317} 312}
318 313
@@ -324,7 +319,7 @@ void Thread::ResumeFromWait() {
324 319
325 // Remove this thread from all other WaitObjects 320 // Remove this thread from all other WaitObjects
326 for (auto wait_object : wait_objects) 321 for (auto wait_object : wait_objects)
327 wait_object.first->RemoveWaitingThread(this); 322 wait_object->RemoveWaitingThread(this);
328 323
329 wait_objects.clear(); 324 wait_objects.clear();
330 325