diff options
| author | 2017-09-30 09:12:18 -0500 | |
|---|---|---|
| committer | 2017-09-30 09:12:18 -0500 | |
| commit | db752b52e84227696af989c2ec1965020c03fac7 (patch) | |
| tree | 04f1e6403bede1890252a0af047e2e149abdde4c /src/core/hle/kernel | |
| parent | Merge pull request #2962 from huwpascoe/static_cast (diff) | |
| parent | Kernel/Threads: When putting a thread to wait, specify a function to execute ... (diff) | |
| download | yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.gz yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.xz yuzu-db752b52e84227696af989c2ec1965020c03fac7.zip | |
Merge pull request #2967 from Subv/thread_wakeup_callbacks
Kernel/Threads: When putting a thread to wait, specify a function to execute when it is awoken
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 13 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 15 | ||||
| -rw-r--r-- | src/core/hle/kernel/wait_object.cpp | 11 |
3 files changed, 26 insertions, 13 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 11f7d2127..2614a260c 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -247,12 +247,15 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 247 | 247 | ||
| 248 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || | 248 | if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 249 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { | 249 | thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { |
| 250 | thread->wait_set_output = false; | 250 | |
| 251 | // Invoke the wakeup callback before clearing the wait objects | ||
| 252 | if (thread->wakeup_callback) | ||
| 253 | thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr); | ||
| 254 | |||
| 251 | // Remove the thread from each of its waiting objects' waitlists | 255 | // Remove the thread from each of its waiting objects' waitlists |
| 252 | for (auto& object : thread->wait_objects) | 256 | for (auto& object : thread->wait_objects) |
| 253 | object->RemoveWaitingThread(thread.get()); | 257 | object->RemoveWaitingThread(thread.get()); |
| 254 | thread->wait_objects.clear(); | 258 | thread->wait_objects.clear(); |
| 255 | thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); | ||
| 256 | } | 259 | } |
| 257 | 260 | ||
| 258 | thread->ResumeFromWait(); | 261 | thread->ResumeFromWait(); |
| @@ -278,6 +281,9 @@ void Thread::ResumeFromWait() { | |||
| 278 | break; | 281 | break; |
| 279 | 282 | ||
| 280 | case THREADSTATUS_READY: | 283 | case THREADSTATUS_READY: |
| 284 | // The thread's wakeup callback must have already been cleared when the thread was first | ||
| 285 | // awoken. | ||
| 286 | ASSERT(wakeup_callback == nullptr); | ||
| 281 | // If the thread is waiting on multiple wait objects, it might be awoken more than once | 287 | // If the thread is waiting on multiple wait objects, it might be awoken more than once |
| 282 | // before actually resuming. We can ignore subsequent wakeups if the thread status has | 288 | // before actually resuming. We can ignore subsequent wakeups if the thread status has |
| 283 | // already been set to THREADSTATUS_READY. | 289 | // already been set to THREADSTATUS_READY. |
| @@ -293,6 +299,8 @@ void Thread::ResumeFromWait() { | |||
| 293 | return; | 299 | return; |
| 294 | } | 300 | } |
| 295 | 301 | ||
| 302 | wakeup_callback = nullptr; | ||
| 303 | |||
| 296 | ready_queue.push_back(current_priority, this); | 304 | ready_queue.push_back(current_priority, this); |
| 297 | status = THREADSTATUS_READY; | 305 | status = THREADSTATUS_READY; |
| 298 | Core::System::GetInstance().PrepareReschedule(); | 306 | Core::System::GetInstance().PrepareReschedule(); |
| @@ -395,7 +403,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 395 | thread->nominal_priority = thread->current_priority = priority; | 403 | thread->nominal_priority = thread->current_priority = priority; |
| 396 | thread->last_running_ticks = CoreTiming::GetTicks(); | 404 | thread->last_running_ticks = CoreTiming::GetTicks(); |
| 397 | thread->processor_id = processor_id; | 405 | thread->processor_id = processor_id; |
| 398 | thread->wait_set_output = false; | ||
| 399 | thread->wait_objects.clear(); | 406 | thread->wait_objects.clear(); |
| 400 | thread->wait_address = 0; | 407 | thread->wait_address = 0; |
| 401 | thread->name = std::move(name); | 408 | thread->name = std::move(name); |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f02e1d43a..4679c2022 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -41,6 +41,11 @@ enum ThreadStatus { | |||
| 41 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated | 41 | THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated |
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | enum class ThreadWakeupReason { | ||
| 45 | Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal. | ||
| 46 | Timeout // The thread was woken up due to a wait timeout. | ||
| 47 | }; | ||
| 48 | |||
| 44 | namespace Kernel { | 49 | namespace Kernel { |
| 45 | 50 | ||
| 46 | class Mutex; | 51 | class Mutex; |
| @@ -199,14 +204,18 @@ public: | |||
| 199 | 204 | ||
| 200 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address | 205 | VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address |
| 201 | 206 | ||
| 202 | /// True if the WaitSynchronizationN output parameter should be set on thread wakeup. | ||
| 203 | bool wait_set_output; | ||
| 204 | |||
| 205 | std::string name; | 207 | std::string name; |
| 206 | 208 | ||
| 207 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. | 209 | /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. |
| 208 | Handle callback_handle; | 210 | Handle callback_handle; |
| 209 | 211 | ||
| 212 | using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr<Thread> thread, | ||
| 213 | SharedPtr<WaitObject> object); | ||
| 214 | // Callback that will be invoked when the thread is resumed from a waiting state. If the thread | ||
| 215 | // was waiting via WaitSynchronizationN then the object will be the last object that became | ||
| 216 | // available. In case of a timeout, the object will be nullptr. | ||
| 217 | std::function<WakeupCallback> wakeup_callback; | ||
| 218 | |||
| 210 | private: | 219 | private: |
| 211 | Thread(); | 220 | Thread(); |
| 212 | ~Thread() override; | 221 | ~Thread() override; |
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 56fdd977f..469554908 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp | |||
| @@ -71,23 +71,20 @@ void WaitObject::WakeupAllWaitingThreads() { | |||
| 71 | while (auto thread = GetHighestPriorityReadyThread()) { | 71 | while (auto thread = GetHighestPriorityReadyThread()) { |
| 72 | if (!thread->IsSleepingOnWaitAll()) { | 72 | if (!thread->IsSleepingOnWaitAll()) { |
| 73 | Acquire(thread.get()); | 73 | Acquire(thread.get()); |
| 74 | // Set the output index of the WaitSynchronizationN call to the index of this object. | ||
| 75 | if (thread->wait_set_output) { | ||
| 76 | thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); | ||
| 77 | thread->wait_set_output = false; | ||
| 78 | } | ||
| 79 | } else { | 74 | } else { |
| 80 | for (auto& object : thread->wait_objects) { | 75 | for (auto& object : thread->wait_objects) { |
| 81 | object->Acquire(thread.get()); | 76 | object->Acquire(thread.get()); |
| 82 | } | 77 | } |
| 83 | // Note: This case doesn't update the output index of WaitSynchronizationN. | ||
| 84 | } | 78 | } |
| 85 | 79 | ||
| 80 | // Invoke the wakeup callback before clearing the wait objects | ||
| 81 | if (thread->wakeup_callback) | ||
| 82 | thread->wakeup_callback(ThreadWakeupReason::Signal, thread, this); | ||
| 83 | |||
| 86 | for (auto& object : thread->wait_objects) | 84 | for (auto& object : thread->wait_objects) |
| 87 | object->RemoveWaitingThread(thread.get()); | 85 | object->RemoveWaitingThread(thread.get()); |
| 88 | thread->wait_objects.clear(); | 86 | thread->wait_objects.clear(); |
| 89 | 87 | ||
| 90 | thread->SetWaitSynchronizationResult(RESULT_SUCCESS); | ||
| 91 | thread->ResumeFromWait(); | 88 | thread->ResumeFromWait(); |
| 92 | } | 89 | } |
| 93 | } | 90 | } |