summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/synchronization.cpp
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-11 17:36:39 -0400
committerGravatar FernandoS272020-02-11 18:47:31 -0400
commitd23d504d776007c1244a85ac1b7bb67c407067b2 (patch)
treed6e992004bf752819084d648ca8b81fd1fc1db18 /src/core/hle/kernel/synchronization.cpp
parentKernel: Change WaitObject to Synchronization object. In order to better refle... (diff)
downloadyuzu-d23d504d776007c1244a85ac1b7bb67c407067b2.tar.gz
yuzu-d23d504d776007c1244a85ac1b7bb67c407067b2.tar.xz
yuzu-d23d504d776007c1244a85ac1b7bb67c407067b2.zip
Kernel: Refactor synchronization to better match RE
Diffstat (limited to 'src/core/hle/kernel/synchronization.cpp')
-rw-r--r--src/core/hle/kernel/synchronization.cpp86
1 files changed, 86 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..25afc162f
--- /dev/null
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -0,0 +1,86 @@
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/kernel.h"
8#include "core/hle/kernel/scheduler.h"
9#include "core/hle/kernel/synchronization.h"
10#include "core/hle/kernel/synchronization_object.h"
11#include "core/hle/kernel/thread.h"
12
13namespace Kernel {
14
15/// Default thread wakeup callback for WaitSynchronization
16static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
17 std::shared_ptr<SynchronizationObject> object,
18 std::size_t index) {
19 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
20
21 if (reason == ThreadWakeupReason::Timeout) {
22 thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
23 return true;
24 }
25
26 ASSERT(reason == ThreadWakeupReason::Signal);
27 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
28 thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
29 return true;
30};
31
32Synchronization::Synchronization(Core::System& system) : system{system} {}
33
34void Synchronization::SignalObject(SynchronizationObject& obj) const {
35 if (obj.IsSignaled()) {
36 obj.WakeupAllWaitingThreads();
37 };
38}
39
40std::pair<ResultCode, Handle> Synchronization::WaitFor(
41 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
42 auto* const thread = system.CurrentScheduler().GetCurrentThread();
43 // Find the first object that is acquirable in the provided list of objects
44 auto itr = std::find_if(sync_objects.begin(), sync_objects.end(),
45 [thread](const std::shared_ptr<SynchronizationObject>& object) {
46 return object->IsSignaled();
47 });
48
49 if (itr != sync_objects.end()) {
50 // We found a ready object, acquire it and set the result value
51 SynchronizationObject* object = itr->get();
52 object->Acquire(thread);
53 u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
54 return {RESULT_SUCCESS, index};
55 }
56
57 // No objects were ready to be acquired, prepare to suspend the thread.
58
59 // If a timeout value of 0 was provided, just return the Timeout error code instead of
60 // suspending the thread.
61 if (nano_seconds == 0) {
62 return {RESULT_TIMEOUT, 0};
63 }
64
65 if (thread->IsSyncCancelled()) {
66 thread->SetSyncCancelled(false);
67 return {ERR_SYNCHRONIZATION_CANCELED, 0};
68 }
69
70 for (auto& object : sync_objects) {
71 object->AddWaitingThread(SharedFrom(thread));
72 }
73
74 thread->SetSynchronizationObjects(std::move(sync_objects));
75 thread->SetStatus(ThreadStatus::WaitSynch);
76
77 // Create an event to wake the thread up after the specified nanosecond delay has passed
78 thread->WakeAfterDelay(nano_seconds);
79 thread->SetWakeupCallback(DefaultThreadWakeupCallback);
80
81 system.PrepareReschedule(thread->GetProcessorID());
82
83 return {RESULT_TIMEOUT, 0};
84}
85
86} // namespace Kernel