summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2020-02-25 16:38:33 -0400
committerGravatar Fernando Sahmkow2020-06-27 11:35:13 -0400
commit3b5b950c895a2db217a3e5c8105cec4498a2534e (patch)
tree2a8e054af30c9aa8039f8faa4b993e2290642184 /src
parentSVC: Remove global HLE Lock. (diff)
downloadyuzu-3b5b950c895a2db217a3e5c8105cec4498a2534e.tar.gz
yuzu-3b5b950c895a2db217a3e5c8105cec4498a2534e.tar.xz
yuzu-3b5b950c895a2db217a3e5c8105cec4498a2534e.zip
SVC: Correct SignalEvent, ClearEvent, ResetSignal, WaitSynchronization, CancelSynchronization, ArbitrateLock
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/mutex.cpp65
-rw-r--r--src/core/hle/kernel/process.cpp1
-rw-r--r--src/core/hle/kernel/readable_event.cpp3
-rw-r--r--src/core/hle/kernel/svc.cpp1
-rw-r--r--src/core/hle/kernel/synchronization.cpp118
-rw-r--r--src/core/hle/kernel/synchronization_object.h5
-rw-r--r--src/core/hle/kernel/thread.cpp14
-rw-r--r--src/core/hle/kernel/thread.h17
8 files changed, 134 insertions, 90 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 7869eb32b..3520c5e49 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -72,42 +72,55 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
72 return ERR_INVALID_ADDRESS; 72 return ERR_INVALID_ADDRESS;
73 } 73 }
74 74
75 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 75 auto& kernel = system.Kernel();
76 std::shared_ptr<Thread> current_thread = 76 std::shared_ptr<Thread> current_thread =
77 SharedFrom(system.CurrentScheduler().GetCurrentThread()); 77 SharedFrom(kernel.CurrentScheduler().GetCurrentThread());
78 std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); 78 {
79 std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); 79 SchedulerLock lock(kernel);
80 // The mutex address must be 4-byte aligned
81 if ((address % sizeof(u32)) != 0) {
82 return ERR_INVALID_ADDRESS;
83 }
80 84
81 // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another 85 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
82 // thread. 86 std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
83 ASSERT(requesting_thread == current_thread); 87 std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle);
84 88
85 const u32 addr_value = system.Memory().Read32(address); 89 // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another
90 // thread.
91 ASSERT(requesting_thread == current_thread);
86 92
87 // If the mutex isn't being held, just return success. 93 current_thread->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
88 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
89 return RESULT_SUCCESS;
90 }
91 94
92 if (holding_thread == nullptr) { 95 const u32 addr_value = system.Memory().Read32(address);
93 LOG_ERROR(Kernel, "Holding thread does not exist! thread_handle={:08X}",
94 holding_thread_handle);
95 return ERR_INVALID_HANDLE;
96 }
97 96
98 // Wait until the mutex is released 97 // If the mutex isn't being held, just return success.
99 current_thread->SetMutexWaitAddress(address); 98 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
100 current_thread->SetWaitHandle(requesting_thread_handle); 99 return RESULT_SUCCESS;
100 }
101 101
102 current_thread->SetStatus(ThreadStatus::WaitMutex); 102 if (holding_thread == nullptr) {
103 current_thread->InvalidateWakeupCallback(); 103 return ERR_INVALID_HANDLE;
104 }
104 105
105 // Update the lock holder thread's priority to prevent priority inversion. 106 // Wait until the mutex is released
106 holding_thread->AddMutexWaiter(current_thread); 107 current_thread->SetMutexWaitAddress(address);
108 current_thread->SetWaitHandle(requesting_thread_handle);
107 109
108 system.PrepareReschedule(); 110 current_thread->SetStatus(ThreadStatus::WaitMutex);
109 111
110 return RESULT_SUCCESS; 112 // Update the lock holder thread's priority to prevent priority inversion.
113 holding_thread->AddMutexWaiter(current_thread);
114 }
115
116 {
117 SchedulerLock lock(kernel);
118 auto* owner = current_thread->GetLockOwner();
119 if (owner != nullptr) {
120 owner->RemoveMutexWaiter(current_thread);
121 }
122 }
123 return current_thread->GetSignalingResult();
111} 124}
112 125
113ResultCode Mutex::Release(VAddr address) { 126ResultCode Mutex::Release(VAddr address) {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 7e26a54f4..cd4b0aa60 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -212,6 +212,7 @@ void Process::UnregisterThread(const Thread* thread) {
212} 212}
213 213
214ResultCode Process::ClearSignalState() { 214ResultCode Process::ClearSignalState() {
215 SchedulerLock lock(system.Kernel());
215 if (status == ProcessStatus::Exited) { 216 if (status == ProcessStatus::Exited) {
216 LOG_ERROR(Kernel, "called on a terminated process instance."); 217 LOG_ERROR(Kernel, "called on a terminated process instance.");
217 return ERR_INVALID_STATE; 218 return ERR_INVALID_STATE;
diff --git a/src/core/hle/kernel/readable_event.cpp b/src/core/hle/kernel/readable_event.cpp
index ef5e19e63..6e286419e 100644
--- a/src/core/hle/kernel/readable_event.cpp
+++ b/src/core/hle/kernel/readable_event.cpp
@@ -6,8 +6,10 @@
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "core/hle/kernel/errors.h" 8#include "core/hle/kernel/errors.h"
9#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/object.h" 10#include "core/hle/kernel/object.h"
10#include "core/hle/kernel/readable_event.h" 11#include "core/hle/kernel/readable_event.h"
12#include "core/hle/kernel/scheduler.h"
11#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
12 14
13namespace Kernel { 15namespace Kernel {
@@ -37,6 +39,7 @@ void ReadableEvent::Clear() {
37} 39}
38 40
39ResultCode ReadableEvent::Reset() { 41ResultCode ReadableEvent::Reset() {
42 SchedulerLock lock(kernel);
40 if (!is_signaled) { 43 if (!is_signaled) {
41 LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}", 44 LOG_TRACE(Kernel, "Handle is not signaled! object_id={}, object_type={}, object_name={}",
42 GetObjectId(), GetTypeName(), GetName()); 45 GetObjectId(), GetTypeName(), GetName());
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index a071b0c09..0d905c0ca 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -448,7 +448,6 @@ static ResultCode CancelSynchronization(Core::System& system, Handle thread_hand
448 } 448 }
449 449
450 thread->CancelWait(); 450 thread->CancelWait();
451 system.PrepareReschedule(thread->GetProcessorID());
452 return RESULT_SUCCESS; 451 return RESULT_SUCCESS;
453} 452}
454 453
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
diff --git a/src/core/hle/kernel/synchronization_object.h b/src/core/hle/kernel/synchronization_object.h
index 741c31faf..0a0d069e0 100644
--- a/src/core/hle/kernel/synchronization_object.h
+++ b/src/core/hle/kernel/synchronization_object.h
@@ -12,6 +12,7 @@
12namespace Kernel { 12namespace Kernel {
13 13
14class KernelCore; 14class KernelCore;
15class Synchronization;
15class Thread; 16class Thread;
16 17
17/// Class that represents a Kernel object that a thread can be waiting on 18/// Class that represents a Kernel object that a thread can be waiting on
@@ -53,7 +54,7 @@ public:
53 * Wake up all threads waiting on this object that can be awoken, in priority order, 54 * Wake up all threads waiting on this object that can be awoken, in priority order,
54 * and set the synchronization result and output of the thread. 55 * and set the synchronization result and output of the thread.
55 */ 56 */
56 void WakeupAllWaitingThreads(); 57 void /* deprecated */ WakeupAllWaitingThreads();
57 58
58 /** 59 /**
59 * Wakes up a single thread waiting on this object. 60 * Wakes up a single thread waiting on this object.
@@ -62,7 +63,7 @@ public:
62 void WakeupWaitingThread(std::shared_ptr<Thread> thread); 63 void WakeupWaitingThread(std::shared_ptr<Thread> thread);
63 64
64 /// Obtains the highest priority thread that is ready to run from this object's waiting list. 65 /// Obtains the highest priority thread that is ready to run from this object's waiting list.
65 std::shared_ptr<Thread> GetHighestPriorityReadyThread() const; 66 std::shared_ptr<Thread> /* deprecated */ GetHighestPriorityReadyThread() const;
66 67
67 /// Get a const reference to the waiting threads list for debug use 68 /// Get a const reference to the waiting threads list for debug use
68 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const; 69 const std::vector<std::shared_ptr<Thread>>& GetWaitingThreads() const;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index e6bb7c666..5fef3945b 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -139,12 +139,13 @@ ResultCode Thread::Start() {
139} 139}
140 140
141void Thread::CancelWait() { 141void Thread::CancelWait() {
142 SchedulerLock lock(kernel);
142 if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { 143 if (GetSchedulingStatus() != ThreadSchedStatus::Paused) {
143 is_sync_cancelled = true; 144 is_sync_cancelled = true;
144 return; 145 return;
145 } 146 }
146 is_sync_cancelled = false; 147 is_sync_cancelled = false;
147 SetWaitSynchronizationResult(ERR_SYNCHRONIZATION_CANCELED); 148 SetSynchronizationResults(nullptr, ERR_SYNCHRONIZATION_CANCELED);
148 ResumeFromWait(); 149 ResumeFromWait();
149} 150}
150 151
@@ -258,13 +259,16 @@ void Thread::SetPriority(u32 priority) {
258} 259}
259 260
260void Thread::SetWaitSynchronizationResult(ResultCode result) { 261void Thread::SetWaitSynchronizationResult(ResultCode result) {
261 context_32.cpu_registers[0] = result.raw; 262 UNREACHABLE();
262 context_64.cpu_registers[0] = result.raw;
263} 263}
264 264
265void Thread::SetWaitSynchronizationOutput(s32 output) { 265void Thread::SetWaitSynchronizationOutput(s32 output) {
266 context_32.cpu_registers[1] = output; 266 UNREACHABLE();
267 context_64.cpu_registers[1] = output; 267}
268
269void Thread::SetSynchronizationResults(SynchronizationObject* object, ResultCode result) {
270 signaling_object = object;
271 signaling_result = result;
268} 272}
269 273
270s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const { 274s32 Thread::GetSynchronizationObjectIndex(std::shared_ptr<SynchronizationObject> object) const {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 29fe5483b..a8ae1a66f 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -259,13 +259,23 @@ public:
259 * Sets the result after the thread awakens (from svcWaitSynchronization) 259 * Sets the result after the thread awakens (from svcWaitSynchronization)
260 * @param result Value to set to the returned result 260 * @param result Value to set to the returned result
261 */ 261 */
262 void SetWaitSynchronizationResult(ResultCode result); 262 void /*deprecated*/ SetWaitSynchronizationResult(ResultCode result);
263 263
264 /** 264 /**
265 * Sets the output parameter value after the thread awakens (from svcWaitSynchronization) 265 * Sets the output parameter value after the thread awakens (from svcWaitSynchronization)
266 * @param output Value to set to the output parameter 266 * @param output Value to set to the output parameter
267 */ 267 */
268 void SetWaitSynchronizationOutput(s32 output); 268 void /*deprecated*/ SetWaitSynchronizationOutput(s32 output);
269
270 void SetSynchronizationResults(SynchronizationObject* object, ResultCode result);
271
272 SynchronizationObject* GetSignalingObject() const {
273 return signaling_object;
274 }
275
276 ResultCode GetSignalingResult() const {
277 return signaling_result;
278 }
269 279
270 /** 280 /**
271 * Retrieves the index that this particular object occupies in the list of objects 281 * Retrieves the index that this particular object occupies in the list of objects
@@ -565,6 +575,9 @@ private:
565 /// passed to WaitSynchronization. 575 /// passed to WaitSynchronization.
566 ThreadSynchronizationObjects wait_objects; 576 ThreadSynchronizationObjects wait_objects;
567 577
578 SynchronizationObject* signaling_object;
579 ResultCode signaling_result{RESULT_SUCCESS};
580
568 /// List of threads that are waiting for a mutex that is held by this thread. 581 /// List of threads that are waiting for a mutex that is held by this thread.
569 MutexWaitingThreads wait_mutex_threads; 582 MutexWaitingThreads wait_mutex_threads;
570 583