diff options
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 61378211f..690cb20b3 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) { if (thread->status == THREADSTATUS_WAIT_SYNCH_ANY || thread->status == THREADSTATUS_WAIT_SYNCH_ALL || thread->status == THREADSTATUS_WAIT_ARB) { - thread->wait_set_output = false; + + // Invoke the wakeup callback before clearing the wait objects + if (thread->wakeup_callback) + thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr); + // Remove the thread from each of its waiting objects' waitlists for (auto& object : thread->wait_objects) object->RemoveWaitingThread(thread.get()); thread->wait_objects.clear(); - thread->SetWaitSynchronizationResult(RESULT_TIMEOUT); } thread->ResumeFromWait(); @@ -278,6 +281,9 @@ void Thread::ResumeFromWait() { break; case THREADSTATUS_READY: + // The thread's wakeup callback must have already been cleared when the thread was first + // awoken. + ASSERT(wakeup_callback == nullptr); // If the thread is waiting on multiple wait objects, it might be awoken more than once // before actually resuming. We can ignore subsequent wakeups if the thread status has // already been set to THREADSTATUS_READY. @@ -293,6 +299,8 @@ void Thread::ResumeFromWait() { return; } + wakeup_callback = nullptr; + ready_queue.push_back(current_priority, this); status = THREADSTATUS_READY; Core::System::GetInstance().PrepareReschedule(); @@ -394,7 +402,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->nominal_priority = thread->current_priority = priority; thread->last_running_ticks = CoreTiming::GetTicks(); thread->processor_id = processor_id; - thread->wait_set_output = false; thread->wait_objects.clear(); thread->wait_address = 0; thread->name = std::move(name); diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 6a3566f15..328f1a86a 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -41,6 +41,11 @@ enum ThreadStatus { THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated }; +enum class ThreadWakeupReason { + Signal, // The thread was woken up by WakeupAllWaitingThreads due to an object signal. + Timeout // The thread was woken up due to a wait timeout. +}; + namespace Kernel { class Mutex; @@ -197,14 +202,18 @@ public: VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address - /// True if the WaitSynchronizationN output parameter should be set on thread wakeup. - bool wait_set_output; - std::string name; /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. Handle callback_handle; + using WakeupCallback = void(ThreadWakeupReason reason, SharedPtr<Thread> thread, + SharedPtr<WaitObject> object); + // Callback that will be invoked when the thread is resumed from a waiting state. If the thread + // was waiting via WaitSynchronizationN then the object will be the last object that became + // available. In case of a timeout, the object will be nullptr. + std::function<WakeupCallback> wakeup_callback; + private: Thread(); ~Thread() override; diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index f245eda6c..1ced26905 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp @@ -71,23 +71,20 @@ void WaitObject::WakeupAllWaitingThreads() { while (auto thread = GetHighestPriorityReadyThread()) { if (!thread->IsSleepingOnWaitAll()) { Acquire(thread.get()); - // Set the output index of the WaitSynchronizationN call to the index of this object. - if (thread->wait_set_output) { - thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this)); - thread->wait_set_output = false; - } } else { for (auto& object : thread->wait_objects) { object->Acquire(thread.get()); } - // Note: This case doesn't update the output index of WaitSynchronizationN. } + // Invoke the wakeup callback before clearing the wait objects + if (thread->wakeup_callback) + thread->wakeup_callback(ThreadWakeupReason::Signal, thread, this); + for (auto& object : thread->wait_objects) object->RemoveWaitingThread(thread.get()); thread->wait_objects.clear(); - thread->SetWaitSynchronizationResult(RESULT_SUCCESS); thread->ResumeFromWait(); } } |