summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel
diff options
context:
space:
mode:
authorSebastian Valle <subv2112@gmail.com>2017-09-30 16:12:18 +0200
committerGitHub <noreply@github.com>2017-09-30 16:12:18 +0200
commitdb752b52e84227696af989c2ec1965020c03fac7 (patch)
tree04f1e6403bede1890252a0af047e2e149abdde4c /src/core/hle/kernel
parentMerge pull request #2962 from huwpascoe/static_cast (diff)
parentKernel/Threads: When putting a thread to wait, specify a function to execute when it is awoken. (diff)
downloadyuzu-db752b52e84227696af989c2ec1965020c03fac7.tar
yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.gz
yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.bz2
yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.lz
yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.xz
yuzu-db752b52e84227696af989c2ec1965020c03fac7.tar.zst
yuzu-db752b52e84227696af989c2ec1965020c03fac7.zip
Diffstat (limited to 'src/core/hle/kernel')
-rw-r--r--src/core/hle/kernel/thread.cpp13
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/kernel/wait_object.cpp11
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) {
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();
@@ -395,7 +403,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 f02e1d43a..4679c2022 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;
@@ -199,14 +204,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 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() {
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();
}
}