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.cpp118
1 files changed, 64 insertions, 54 deletions
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
index dc37fad1a..b36e550a0 100644
--- a/src/core/hle/kernel/synchronization.cpp
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -10,78 +10,88 @@
10#include "core/hle/kernel/synchronization.h" 10#include "core/hle/kernel/synchronization.h"
11#include "core/hle/kernel/synchronization_object.h" 11#include "core/hle/kernel/synchronization_object.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13#include "core/hle/kernel/time_manager.h"
13 14
14namespace Kernel { 15namespace Kernel {
15 16
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} {} 17Synchronization::Synchronization(Core::System& system) : system{system} {}
34 18
35void Synchronization::SignalObject(SynchronizationObject& obj) const { 19void Synchronization::SignalObject(SynchronizationObject& obj) const {
20 SchedulerLock lock(system.Kernel());
36 if (obj.IsSignaled()) { 21 if (obj.IsSignaled()) {
37 obj.WakeupAllWaitingThreads(); 22 for (auto thread : obj.GetWaitingThreads()) {
23 if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
24 thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
25 thread->ResumeFromWait();
26 }
27 }
38 } 28 }
39} 29}
40 30
41std::pair<ResultCode, Handle> Synchronization::WaitFor( 31std::pair<ResultCode, Handle> Synchronization::WaitFor(
42 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { 32 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
33 auto& kernel = system.Kernel();
43 auto* const thread = system.CurrentScheduler().GetCurrentThread(); 34 auto* const thread = system.CurrentScheduler().GetCurrentThread();
44 // Find the first object that is acquirable in the provided list of objects 35 Handle event_handle = InvalidHandle;
45 const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), 36 {
46 [thread](const std::shared_ptr<SynchronizationObject>& object) { 37 SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
47 return object->IsSignaled(); 38 const auto itr =
48 }); 39 std::find_if(sync_objects.begin(), sync_objects.end(),
49 40 [thread](const std::shared_ptr<SynchronizationObject>& object) {
50 if (itr != sync_objects.end()) { 41 return object->IsSignaled();
51 // We found a ready object, acquire it and set the result value 42 });
52 SynchronizationObject* object = itr->get(); 43
53 object->Acquire(thread); 44 if (itr != sync_objects.end()) {
54 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); 45 // We found a ready object, acquire it and set the result value
55 return {RESULT_SUCCESS, index}; 46 SynchronizationObject* object = itr->get();
47 object->Acquire(thread);
48 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
49 lock.CancelSleep();
50 return {RESULT_SUCCESS, index};
51 }
52
53 if (nano_seconds == 0) {
54 lock.CancelSleep();
55 return {RESULT_TIMEOUT, InvalidHandle};
56 }
57
58 /// TODO(Blinkhawk): Check for termination pending
59
60 if (thread->IsSyncCancelled()) {
61 thread->SetSyncCancelled(false);
62 lock.CancelSleep();
63 return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
64 }
65
66 for (auto& object : sync_objects) {
67 object->AddWaitingThread(SharedFrom(thread));
68 }
69 thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
70 thread->SetStatus(ThreadStatus::WaitSynch);
56 } 71 }
57 72
58 // No objects were ready to be acquired, prepare to suspend the thread. 73 if (event_handle != InvalidHandle) {
59 74 auto& time_manager = kernel.TimeManager();
60 // If a timeout value of 0 was provided, just return the Timeout error code instead of 75 time_manager.UnscheduleTimeEvent(event_handle);
61 // suspending the thread.
62 if (nano_seconds == 0) {
63 return {RESULT_TIMEOUT, InvalidHandle};
64 } 76 }
65 77
66 if (thread->IsSyncCancelled()) { 78 {
67 thread->SetSyncCancelled(false); 79 SchedulerLock lock(kernel);
68 return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; 80 ResultCode signaling_result = thread->GetSignalingResult();
81 SynchronizationObject* signaling_object = thread->GetSignalingObject();
82 if (signaling_result == RESULT_SUCCESS) {
83 const auto itr = std::find_if(
84 sync_objects.begin(), sync_objects.end(),
85 [signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
86 return object.get() == signaling_object;
87 });
88 ASSERT(itr != sync_objects.end());
89 signaling_object->Acquire(thread);
90 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
91 return {RESULT_SUCCESS, index};
92 }
93 return {signaling_result, -1};
69 } 94 }
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} 95}
86 96
87} // namespace Kernel 97} // namespace Kernel