summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/synchronization.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2020-06-28 12:37:50 -0400
committerGravatar GitHub2020-06-28 12:37:50 -0400
commitb05795d704e0c194215f815a5703db09e524b59a (patch)
treeecf4023b4ee0c91555c1d8263762fcb9dcb04a17 /src/core/hle/kernel/synchronization.cpp
parentMerge pull request #4196 from ogniK5377/nrr-nro-fixes (diff)
parentCore/Common: Address Feedback. (diff)
downloadyuzu-b05795d704e0c194215f815a5703db09e524b59a.tar.gz
yuzu-b05795d704e0c194215f815a5703db09e524b59a.tar.xz
yuzu-b05795d704e0c194215f815a5703db09e524b59a.zip
Merge pull request #3955 from FernandoS27/prometheus-2b
Remake Kernel Scheduling, CPU Management & Boot Management (Prometheus)
Diffstat (limited to 'src/core/hle/kernel/synchronization.cpp')
-rw-r--r--src/core/hle/kernel/synchronization.cpp137
1 files changed, 83 insertions, 54 deletions
diff --git a/src/core/hle/kernel/synchronization.cpp b/src/core/hle/kernel/synchronization.cpp
index dc37fad1a..851b702a5 100644
--- a/src/core/hle/kernel/synchronization.cpp
+++ b/src/core/hle/kernel/synchronization.cpp
@@ -10,78 +10,107 @@
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 auto& kernel = system.Kernel();
21 SchedulerLock lock(kernel);
22 auto& time_manager = kernel.TimeManager();
36 if (obj.IsSignaled()) { 23 if (obj.IsSignaled()) {
37 obj.WakeupAllWaitingThreads(); 24 for (auto thread : obj.GetWaitingThreads()) {
25 if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
26 if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) {
27 ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
28 ASSERT(thread->IsWaitingSync());
29 }
30 thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
31 thread->ResumeFromWait();
32 }
33 }
34 obj.ClearWaitingThreads();
38 } 35 }
39} 36}
40 37
41std::pair<ResultCode, Handle> Synchronization::WaitFor( 38std::pair<ResultCode, Handle> Synchronization::WaitFor(
42 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) { 39 std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
40 auto& kernel = system.Kernel();
43 auto* const thread = system.CurrentScheduler().GetCurrentThread(); 41 auto* const thread = system.CurrentScheduler().GetCurrentThread();
44 // Find the first object that is acquirable in the provided list of objects 42 Handle event_handle = InvalidHandle;
45 const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(), 43 {
46 [thread](const std::shared_ptr<SynchronizationObject>& object) { 44 SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
47 return object->IsSignaled(); 45 const auto itr =
48 }); 46 std::find_if(sync_objects.begin(), sync_objects.end(),
49 47 [thread](const std::shared_ptr<SynchronizationObject>& object) {
50 if (itr != sync_objects.end()) { 48 return object->IsSignaled();
51 // We found a ready object, acquire it and set the result value 49 });
52 SynchronizationObject* object = itr->get(); 50
53 object->Acquire(thread); 51 if (itr != sync_objects.end()) {
54 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr)); 52 // We found a ready object, acquire it and set the result value
55 return {RESULT_SUCCESS, index}; 53 SynchronizationObject* object = itr->get();
54 object->Acquire(thread);
55 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
56 lock.CancelSleep();
57 return {RESULT_SUCCESS, index};
58 }
59
60 if (nano_seconds == 0) {
61 lock.CancelSleep();
62 return {RESULT_TIMEOUT, InvalidHandle};
63 }
64
65 if (thread->IsPendingTermination()) {
66 lock.CancelSleep();
67 return {ERR_THREAD_TERMINATING, InvalidHandle};
68 }
69
70 if (thread->IsSyncCancelled()) {
71 thread->SetSyncCancelled(false);
72 lock.CancelSleep();
73 return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
74 }
75
76 for (auto& object : sync_objects) {
77 object->AddWaitingThread(SharedFrom(thread));
78 }
79
80 thread->SetSynchronizationObjects(&sync_objects);
81 thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
82 thread->SetStatus(ThreadStatus::WaitSynch);
83 thread->SetWaitingSync(true);
56 } 84 }
85 thread->SetWaitingSync(false);
57 86
58 // No objects were ready to be acquired, prepare to suspend the thread. 87 if (event_handle != InvalidHandle) {
59 88 auto& time_manager = kernel.TimeManager();
60 // If a timeout value of 0 was provided, just return the Timeout error code instead of 89 time_manager.UnscheduleTimeEvent(event_handle);
61 // suspending the thread.
62 if (nano_seconds == 0) {
63 return {RESULT_TIMEOUT, InvalidHandle};
64 } 90 }
65 91
66 if (thread->IsSyncCancelled()) { 92 {
67 thread->SetSyncCancelled(false); 93 SchedulerLock lock(kernel);
68 return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle}; 94 ResultCode signaling_result = thread->GetSignalingResult();
95 SynchronizationObject* signaling_object = thread->GetSignalingObject();
96 thread->SetSynchronizationObjects(nullptr);
97 auto shared_thread = SharedFrom(thread);
98 for (auto& obj : sync_objects) {
99 obj->RemoveWaitingThread(shared_thread);
100 }
101 if (signaling_object != nullptr) {
102 const auto itr = std::find_if(
103 sync_objects.begin(), sync_objects.end(),
104 [signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
105 return object.get() == signaling_object;
106 });
107 ASSERT(itr != sync_objects.end());
108 signaling_object->Acquire(thread);
109 const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
110 return {signaling_result, index};
111 }
112 return {signaling_result, -1};
69 } 113 }
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} 114}
86 115
87} // namespace Kernel 116} // namespace Kernel