diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/debugger/wait_tree.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 10 | ||||
| -rw-r--r-- | src/core/hle/svc.cpp | 47 |
4 files changed, 41 insertions, 28 deletions
diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp index 8ff094209..b2e7f4a97 100644 --- a/src/citra_qt/debugger/wait_tree.cpp +++ b/src/citra_qt/debugger/wait_tree.cpp | |||
| @@ -230,7 +230,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 230 | list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes)); | 230 | list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes)); |
| 231 | } | 231 | } |
| 232 | if (thread.status == THREADSTATUS_WAIT_SYNCH) { | 232 | if (thread.status == THREADSTATUS_WAIT_SYNCH) { |
| 233 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, thread.IsSleepingOnWaitAll())); | 233 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, |
| 234 | thread.IsSleepingOnWaitAll())); | ||
| 234 | } | 235 | } |
| 235 | 236 | ||
| 236 | return list; | 237 | return list; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 2ddeffcdd..209d35270 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -50,9 +50,9 @@ SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() { | |||
| 50 | if (thread->current_priority >= candidate_priority) | 50 | if (thread->current_priority >= candidate_priority) |
| 51 | continue; | 51 | continue; |
| 52 | 52 | ||
| 53 | bool ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), [](const SharedPtr<WaitObject>& object) { | 53 | bool ready_to_run = |
| 54 | return object->ShouldWait(); | 54 | std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(), |
| 55 | }); | 55 | [](const SharedPtr<WaitObject>& object) { return object->ShouldWait(); }); |
| 56 | if (ready_to_run) { | 56 | if (ready_to_run) { |
| 57 | candidate = thread.get(); | 57 | candidate = thread.get(); |
| 58 | candidate_priority = thread->current_priority; | 58 | candidate_priority = thread->current_priority; |
| @@ -83,7 +83,8 @@ void WaitObject::WakeupAllWaitingThreads() { | |||
| 83 | 83 | ||
| 84 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | 84 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); |
| 85 | thread->ResumeFromWait(); | 85 | thread->ResumeFromWait(); |
| 86 | // Note: Removing the thread from the object's waitlist will be done by GetHighestPriorityReadyThread | 86 | // Note: Removing the thread from the object's waitlist will be |
| 87 | // done by GetHighestPriorityReadyThread. | ||
| 87 | } | 88 | } |
| 88 | } | 89 | } |
| 89 | 90 | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 4c254cb9d..238359fc5 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -178,17 +178,19 @@ public: | |||
| 178 | /// Mutexes currently held by this thread, which will be released when it exits. | 178 | /// Mutexes currently held by this thread, which will be released when it exits. |
| 179 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; | 179 | boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; |
| 180 | 180 | ||
| 181 | SharedPtr<Process> owner_process; ///< Process that owns this thread | 181 | SharedPtr<Process> owner_process; ///< Process that owns this thread |
| 182 | 182 | ||
| 183 | /// Objects that the thread is waiting on. | 183 | /// Objects that the thread is waiting on. |
| 184 | /// This is only populated when the thread should wait for all the objects to become ready. | 184 | /// This is only populated when the thread should wait for all the objects to become ready. |
| 185 | std::vector<SharedPtr<WaitObject>> wait_objects; | 185 | std::vector<SharedPtr<WaitObject>> wait_objects; |
| 186 | 186 | ||
| 187 | boost::container::flat_map<int, s32> wait_objects_index; ///< Mapping of Object ids to their position in the last waitlist that this object waited on. | 187 | /// Mapping of Object ids to their position in the last waitlist that this object waited on. |
| 188 | boost::container::flat_map<int, s32> wait_objects_index; | ||
| 188 | 189 | ||
| 189 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address | 190 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address |
| 190 | 191 | ||
| 191 | bool wait_set_output; ///< True if the WaitSynchronizationN output parameter should be set on thread wakeup | 192 | /// True if the WaitSynchronizationN output parameter should be set on thread wakeup. |
| 193 | bool wait_set_output; | ||
| 192 | 194 | ||
| 193 | std::string name; | 195 | std::string name; |
| 194 | 196 | ||
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index c81c14443..a4a00d9b2 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -264,14 +264,16 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { | |||
| 264 | return ERR_SYNC_TIMEOUT; | 264 | return ERR_SYNC_TIMEOUT; |
| 265 | 265 | ||
| 266 | object->AddWaitingThread(thread); | 266 | object->AddWaitingThread(thread); |
| 267 | // TODO(Subv): Perform things like update the mutex lock owner's priority to prevent priority inversion. | 267 | // TODO(Subv): Perform things like update the mutex lock owner's priority to |
| 268 | // Currently this is done in Mutex::ShouldWait, but it should be moved to a function that is called from here. | 268 | // prevent priority inversion. Currently this is done in Mutex::ShouldWait, |
| 269 | // but it should be moved to a function that is called from here. | ||
| 269 | thread->status = THREADSTATUS_WAIT_SYNCH; | 270 | thread->status = THREADSTATUS_WAIT_SYNCH; |
| 270 | 271 | ||
| 271 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 272 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 272 | thread->WakeAfterDelay(nano_seconds); | 273 | thread->WakeAfterDelay(nano_seconds); |
| 273 | 274 | ||
| 274 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a signal in its wait objects. | 275 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread |
| 276 | // resumes due to a signal in its wait objects. | ||
| 275 | // Otherwise we retain the default value of timeout. | 277 | // Otherwise we retain the default value of timeout. |
| 276 | return ERR_SYNC_TIMEOUT; | 278 | return ERR_SYNC_TIMEOUT; |
| 277 | } | 279 | } |
| @@ -316,20 +318,22 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 316 | thread->wait_objects_index.clear(); | 318 | thread->wait_objects_index.clear(); |
| 317 | 319 | ||
| 318 | if (wait_all) { | 320 | if (wait_all) { |
| 319 | bool all_available = std::all_of(objects.begin(), objects.end(), [](const ObjectPtr& object) { | 321 | bool all_available = |
| 320 | return !object->ShouldWait(); | 322 | std::all_of(objects.begin(), objects.end(), |
| 321 | }); | 323 | [](const ObjectPtr& object) { return !object->ShouldWait(); }); |
| 322 | if (all_available) { | 324 | if (all_available) { |
| 323 | // We can acquire all objects right now, do so. | 325 | // We can acquire all objects right now, do so. |
| 324 | for (auto& object : objects) | 326 | for (auto& object : objects) |
| 325 | object->Acquire(); | 327 | object->Acquire(); |
| 326 | // Note: In this case, the `out` parameter is not set, and retains whatever value it had before. | 328 | // Note: In this case, the `out` parameter is not set, |
| 329 | // and retains whatever value it had before. | ||
| 327 | return RESULT_SUCCESS; | 330 | return RESULT_SUCCESS; |
| 328 | } | 331 | } |
| 329 | 332 | ||
| 330 | // Not all objects were available right now, prepare to suspend the thread. | 333 | // Not all objects were available right now, prepare to suspend the thread. |
| 331 | 334 | ||
| 332 | // If a timeout value of 0 was provided, just return the Timeout error code instead of suspending the thread. | 335 | // If a timeout value of 0 was provided, just return the Timeout error code instead of |
| 336 | // suspending the thread. | ||
| 333 | if (nano_seconds == 0) | 337 | if (nano_seconds == 0) |
| 334 | return ERR_SYNC_TIMEOUT; | 338 | return ERR_SYNC_TIMEOUT; |
| 335 | 339 | ||
| @@ -339,8 +343,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 339 | // Add the thread to each of the objects' waiting threads. | 343 | // Add the thread to each of the objects' waiting threads. |
| 340 | for (auto& object : objects) { | 344 | for (auto& object : objects) { |
| 341 | object->AddWaitingThread(thread); | 345 | object->AddWaitingThread(thread); |
| 342 | // TODO(Subv): Perform things like update the mutex lock owner's priority to prevent priority inversion. | 346 | // TODO(Subv): Perform things like update the mutex lock owner's priority to |
| 343 | // Currently this is done in Mutex::ShouldWait, but it should be moved to a function that is called from here. | 347 | // prevent priority inversion. Currently this is done in Mutex::ShouldWait, |
| 348 | // but it should be moved to a function that is called from here. | ||
| 344 | } | 349 | } |
| 345 | 350 | ||
| 346 | // Set the thread's waitlist to the list of objects passed to WaitSynchronizationN | 351 | // Set the thread's waitlist to the list of objects passed to WaitSynchronizationN |
| @@ -351,13 +356,13 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 351 | 356 | ||
| 352 | // This value gets set to -1 by default in this case, it is not modified after this. | 357 | // This value gets set to -1 by default in this case, it is not modified after this. |
| 353 | *out = -1; | 358 | *out = -1; |
| 354 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a signal in one of its wait objects. | 359 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to |
| 360 | // a signal in one of its wait objects. | ||
| 355 | return ERR_SYNC_TIMEOUT; | 361 | return ERR_SYNC_TIMEOUT; |
| 356 | } else { | 362 | } else { |
| 357 | // Find the first object that is acquirable in the provided list of objects | 363 | // Find the first object that is acquirable in the provided list of objects |
| 358 | auto itr = std::find_if(objects.begin(), objects.end(), [](const ObjectPtr& object) { | 364 | auto itr = std::find_if(objects.begin(), objects.end(), |
| 359 | return !object->ShouldWait(); | 365 | [](const ObjectPtr& object) { return !object->ShouldWait(); }); |
| 360 | }); | ||
| 361 | 366 | ||
| 362 | if (itr != objects.end()) { | 367 | if (itr != objects.end()) { |
| 363 | // We found a ready object, acquire it and set the result value | 368 | // We found a ready object, acquire it and set the result value |
| @@ -369,7 +374,8 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 369 | 374 | ||
| 370 | // No objects were ready to be acquired, prepare to suspend the thread. | 375 | // No objects were ready to be acquired, prepare to suspend the thread. |
| 371 | 376 | ||
| 372 | // If a timeout value of 0 was provided, just return the Timeout error code instead of suspending the thread. | 377 | // If a timeout value of 0 was provided, just return the Timeout error code instead of |
| 378 | // suspending the thread. | ||
| 373 | if (nano_seconds == 0) | 379 | if (nano_seconds == 0) |
| 374 | return ERR_SYNC_TIMEOUT; | 380 | return ERR_SYNC_TIMEOUT; |
| 375 | 381 | ||
| @@ -385,16 +391,19 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou | |||
| 385 | // Set the index of this object in the mapping of Objects -> index for this thread. | 391 | // Set the index of this object in the mapping of Objects -> index for this thread. |
| 386 | thread->wait_objects_index[object->GetObjectId()] = static_cast<int>(i); | 392 | thread->wait_objects_index[object->GetObjectId()] = static_cast<int>(i); |
| 387 | object->AddWaitingThread(thread); | 393 | object->AddWaitingThread(thread); |
| 388 | // TODO(Subv): Perform things like update the mutex lock owner's priority to prevent priority inversion. | 394 | // TODO(Subv): Perform things like update the mutex lock owner's priority to |
| 389 | // Currently this is done in Mutex::ShouldWait, but it should be moved to a function that is called from here. | 395 | // prevent priority inversion. Currently this is done in Mutex::ShouldWait, |
| 396 | // but it should be moved to a function that is called from here. | ||
| 390 | } | 397 | } |
| 391 | 398 | ||
| 392 | // Note: If no handles and no timeout were given, then the thread will deadlock, this is consistent with hardware behavior. | 399 | // Note: If no handles and no timeout were given, then the thread will deadlock, this is |
| 400 | // consistent with hardware behavior. | ||
| 393 | 401 | ||
| 394 | // Create an event to wake the thread up after the specified nanosecond delay has passed | 402 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 395 | thread->WakeAfterDelay(nano_seconds); | 403 | thread->WakeAfterDelay(nano_seconds); |
| 396 | 404 | ||
| 397 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a signal in one of its wait objects. | 405 | // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a |
| 406 | // signal in one of its wait objects. | ||
| 398 | // Otherwise we retain the default value of timeout, and -1 in the out parameter | 407 | // Otherwise we retain the default value of timeout, and -1 in the out parameter |
| 399 | thread->wait_set_output = true; | 408 | thread->wait_set_output = true; |
| 400 | *out = -1; | 409 | *out = -1; |