summaryrefslogtreecommitdiffstats
path: root/src/core/hle/kernel/synchronization_object.cpp
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2020-02-14 20:40:20 +0100
committerGitHub <noreply@github.com>2020-02-14 20:40:20 +0100
commitf552d553bac1374c583d748dad27f8c86e86c4a0 (patch)
tree1da4aa037ff417fa4fd43bffac267dcb2b55a72d /src/core/hle/kernel/synchronization_object.cpp
parentMerge pull request #3379 from ReinUsesLisp/cbuf-offset (diff)
parentCore: Correct compilition in GCC (diff)
downloadyuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar
yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.gz
yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.bz2
yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.lz
yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.xz
yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.tar.zst
yuzu-f552d553bac1374c583d748dad27f8c86e86c4a0.zip
Diffstat (limited to 'src/core/hle/kernel/synchronization_object.cpp')
-rw-r--r--src/core/hle/kernel/synchronization_object.cpp109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/core/hle/kernel/synchronization_object.cpp b/src/core/hle/kernel/synchronization_object.cpp
new file mode 100644
index 000000000..43f3eef18
--- /dev/null
+++ b/src/core/hle/kernel/synchronization_object.cpp
@@ -0,0 +1,109 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/object.h"
+#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/synchronization.h"
+#include "core/hle/kernel/synchronization_object.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
+SynchronizationObject::~SynchronizationObject() = default;
+
+void SynchronizationObject::Signal() {
+ kernel.Synchronization().SignalObject(*this);
+}
+
+void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
+ auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
+ if (itr == waiting_threads.end())
+ waiting_threads.push_back(std::move(thread));
+}
+
+void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
+ auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
+ // If a thread passed multiple handles to the same object,
+ // the kernel might attempt to remove the thread from the object's
+ // waiting threads list multiple times.
+ if (itr != waiting_threads.end())
+ waiting_threads.erase(itr);
+}
+
+std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
+ Thread* candidate = nullptr;
+ u32 candidate_priority = THREADPRIO_LOWEST + 1;
+
+ for (const auto& thread : waiting_threads) {
+ const ThreadStatus thread_status = thread->GetStatus();
+
+ // The list of waiting threads must not contain threads that are not waiting to be awakened.
+ ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
+ thread_status == ThreadStatus::WaitHLEEvent,
+ "Inconsistent thread statuses in waiting_threads");
+
+ if (thread->GetPriority() >= candidate_priority)
+ continue;
+
+ if (ShouldWait(thread.get()))
+ continue;
+
+ candidate = thread.get();
+ candidate_priority = thread->GetPriority();
+ }
+
+ return SharedFrom(candidate);
+}
+
+void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
+ ASSERT(!ShouldWait(thread.get()));
+
+ if (!thread) {
+ return;
+ }
+
+ if (thread->IsSleepingOnWait()) {
+ for (const auto& object : thread->GetSynchronizationObjects()) {
+ ASSERT(!object->ShouldWait(thread.get()));
+ object->Acquire(thread.get());
+ }
+ } else {
+ Acquire(thread.get());
+ }
+
+ const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
+
+ thread->ClearSynchronizationObjects();
+
+ thread->CancelWakeupTimer();
+
+ bool resume = true;
+ if (thread->HasWakeupCallback()) {
+ resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this),
+ index);
+ }
+ if (resume) {
+ thread->ResumeFromWait();
+ kernel.PrepareReschedule(thread->GetProcessorID());
+ }
+}
+
+void SynchronizationObject::WakeupAllWaitingThreads() {
+ while (auto thread = GetHighestPriorityReadyThread()) {
+ WakeupWaitingThread(thread);
+ }
+}
+
+const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
+ return waiting_threads;
+}
+
+} // namespace Kernel