summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/synchronization.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/synchronization.cpp')
-rw-r--r--src/core/hle/kernel/synchronization.cpp87
1 files changed, 87 insertions, 0 deletions
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
new file mode 100644
index 000000000..dc37fad1a
--- /dev/null
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -0,0 +1,87 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/hle/kernel/errors.h"
7#include "core/hle/kernel/handle_table.h"
8#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/scheduler.h"
10#include "core/hle/kernel/synchronization.h"
11#include "core/hle/kernel/synchronization_object.h"
12#include "core/hle/kernel/thread.h"
13
14namespace Kernel {
15
16/// Default thread wakeup callback for WaitSynchronization
17static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
18 std::shared_ptr<SynchronizationObject> object,
19 std::size_t index) {
20 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
21
22 if (reason == ThreadWakeupReason::Timeout) {
23 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
24 return true;
25 }
26
27 ASSERT(reason == ThreadWakeupReason::Signal);
28 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
29 thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
30 return true;
31}
32
33Synchronization::Synchronization(Core::System& system) : system{system} {}
34
35void Synchronization::SignalObject(SynchronizationObject& obj) const {
36 if (obj.IsSignaled()) {
37 obj.WakeupAllWaitingThreads();
38 }
39}
40
41std::pair<ResultCode, Handle> Synchronization::WaitFor(
42 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
43 auto* const thread = system.CurrentScheduler().GetCurrentThread();
44 // Find the first object that is acquirable in the provided list of objects
45 const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(),
46 [thread](const std::shared_ptr<SynchronizationObject>& object) {
47 return object->IsSignaled();
48 });
49
50 if (itr != sync_objects.end()) {
51 // We found a ready object, acquire it and set the result value
52 SynchronizationObject* object = itr->get();
53 object->Acquire(thread);
54 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
55 return {RESULT_SUCCESS, index};
56 }
57
58 // No objects were ready to be acquired, prepare to suspend the thread.
59
60 // If a timeout value of 0 was provided, just return the Timeout error code instead of
61 // suspending the thread.
62 if (nano_seconds == 0) {
63 return {RESULT_TIMEOUT, InvalidHandle};
64 }
65
66 if (thread->IsSyncCancelled()) {
67 thread->SetSyncCancelled(false);
68 return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
69 }
70
71 for (auto& object : sync_objects) {
72 object->AddWaitingThread(SharedFrom(thread));
73 }
74
75 thread->SetSynchronizationObjects(std::move(sync_objects));
76 thread->SetStatus(ThreadStatus::WaitSynch);
77
78 // Create an event to wake the thread up after the specified nanosecond delay has passed
79 thread->WakeAfterDelay(nano_seconds);
80 thread->SetWakeupCallback(DefaultThreadWakeupCallback);
81
82 system.PrepareReschedule(thread->GetProcessorID());
83
84 return {RESULT_TIMEOUT, InvalidHandle};
85}
86
87} // namespace Kernel