summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/mutex.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/mutex.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/mutex.cpp')
-rw-r--r--src/core/hle/kernel/mutex.cpp118
1 files changed, 66 insertions, 52 deletions
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 7869eb32b..8f6c944d1 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -34,8 +34,6 @@ static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThr
34 if (thread->GetMutexWaitAddress() != mutex_addr) 34 if (thread->GetMutexWaitAddress() != mutex_addr)
35 continue; 35 continue;
36 36
37 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
38
39 ++num_waiters; 37 ++num_waiters;
40 if (highest_priority_thread == nullptr || 38 if (highest_priority_thread == nullptr ||
41 thread->GetPriority() < highest_priority_thread->GetPriority()) { 39 thread->GetPriority() < highest_priority_thread->GetPriority()) {
@@ -49,6 +47,7 @@ static std::pair<std::shared_ptr<Thread>, u32> GetHighestPriorityMutexWaitingThr
49/// Update the mutex owner field of all threads waiting on the mutex to point to the new owner. 47/// Update the mutex owner field of all threads waiting on the mutex to point to the new owner.
50static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr<Thread> current_thread, 48static void TransferMutexOwnership(VAddr mutex_addr, std::shared_ptr<Thread> current_thread,
51 std::shared_ptr<Thread> new_owner) { 49 std::shared_ptr<Thread> new_owner) {
50 current_thread->RemoveMutexWaiter(new_owner);
52 const auto threads = current_thread->GetMutexWaitingThreads(); 51 const auto threads = current_thread->GetMutexWaitingThreads();
53 for (const auto& thread : threads) { 52 for (const auto& thread : threads) {
54 if (thread->GetMutexWaitAddress() != mutex_addr) 53 if (thread->GetMutexWaitAddress() != mutex_addr)
@@ -72,85 +71,100 @@ ResultCode Mutex::TryAcquire(VAddr address, Handle holding_thread_handle,
72 return ERR_INVALID_ADDRESS; 71 return ERR_INVALID_ADDRESS;
73 } 72 }
74 73
75 const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); 74 auto& kernel = system.Kernel();
76 std::shared_ptr<Thread> current_thread = 75 std::shared_ptr<Thread> current_thread =
77 SharedFrom(system.CurrentScheduler().GetCurrentThread()); 76 SharedFrom(kernel.CurrentScheduler().GetCurrentThread());
78 std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle); 77 {
79 std::shared_ptr<Thread> requesting_thread = handle_table.Get<Thread>(requesting_thread_handle); 78 SchedulerLock lock(kernel);
79 // The mutex address must be 4-byte aligned
80 if ((address % sizeof(u32)) != 0) {
81 return ERR_INVALID_ADDRESS;
82 }
80 83
81 // TODO(Subv): It is currently unknown if it is possible to lock a mutex in behalf of another 84 const auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
82 // thread. 85 std::shared_ptr<Thread> holding_thread = handle_table.Get<Thread>(holding_thread_handle);
83 ASSERT(requesting_thread == current_thread); 86 std::shared_ptr<Thread> requesting_thread =
87 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
90 // another 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}", 96
94 holding_thread_handle); 97 // If the mutex isn't being held, just return success.
95 return ERR_INVALID_HANDLE; 98 if (addr_value != (holding_thread_handle | Mutex::MutexHasWaitersFlag)) {
96 } 99 return RESULT_SUCCESS;
100 }
97 101
98 // Wait until the mutex is released 102 if (holding_thread == nullptr) {
99 current_thread->SetMutexWaitAddress(address); 103 return ERR_INVALID_HANDLE;
100 current_thread->SetWaitHandle(requesting_thread_handle); 104 }
101 105
102 current_thread->SetStatus(ThreadStatus::WaitMutex); 106 // Wait until the mutex is released
103 current_thread->InvalidateWakeupCallback(); 107 current_thread->SetMutexWaitAddress(address);
108 current_thread->SetWaitHandle(requesting_thread_handle);
104 109
105 // Update the lock holder thread's priority to prevent priority inversion. 110 current_thread->SetStatus(ThreadStatus::WaitMutex);
106 holding_thread->AddMutexWaiter(current_thread);
107 111
108 system.PrepareReschedule(); 112 // Update the lock holder thread's priority to prevent priority inversion.
113 holding_thread->AddMutexWaiter(current_thread);
114 }
109 115
110 return RESULT_SUCCESS; 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) { 126std::pair<ResultCode, std::shared_ptr<Thread>> Mutex::Unlock(std::shared_ptr<Thread> owner,
127 VAddr address) {
114 // The mutex address must be 4-byte aligned 128 // The mutex address must be 4-byte aligned
115 if ((address % sizeof(u32)) != 0) { 129 if ((address % sizeof(u32)) != 0) {
116 LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address); 130 LOG_ERROR(Kernel, "Address is not 4-byte aligned! address={:016X}", address);
117 return ERR_INVALID_ADDRESS; 131 return {ERR_INVALID_ADDRESS, nullptr};
118 } 132 }
119 133
120 std::shared_ptr<Thread> current_thread = 134 auto [new_owner, num_waiters] = GetHighestPriorityMutexWaitingThread(owner, address);
121 SharedFrom(system.CurrentScheduler().GetCurrentThread()); 135 if (new_owner == nullptr) {
122 auto [thread, num_waiters] = GetHighestPriorityMutexWaitingThread(current_thread, address);
123
124 // There are no more threads waiting for the mutex, release it completely.
125 if (thread == nullptr) {
126 system.Memory().Write32(address, 0); 136 system.Memory().Write32(address, 0);
127 return RESULT_SUCCESS; 137 return {RESULT_SUCCESS, nullptr};
128 } 138 }
129
130 // Transfer the ownership of the mutex from the previous owner to the new one. 139 // Transfer the ownership of the mutex from the previous owner to the new one.
131 TransferMutexOwnership(address, current_thread, thread); 140 TransferMutexOwnership(address, owner, new_owner);
132 141 u32 mutex_value = new_owner->GetWaitHandle();
133 u32 mutex_value = thread->GetWaitHandle();
134
135 if (num_waiters >= 2) { 142 if (num_waiters >= 2) {
136 // Notify the guest that there are still some threads waiting for the mutex 143 // Notify the guest that there are still some threads waiting for the mutex
137 mutex_value |= Mutex::MutexHasWaitersFlag; 144 mutex_value |= Mutex::MutexHasWaitersFlag;
138 } 145 }
146 new_owner->SetSynchronizationResults(nullptr, RESULT_SUCCESS);
147 new_owner->SetLockOwner(nullptr);
148 new_owner->ResumeFromWait();
139 149
140 // Grant the mutex to the next waiting thread and resume it.
141 system.Memory().Write32(address, mutex_value); 150 system.Memory().Write32(address, mutex_value);
151 return {RESULT_SUCCESS, new_owner};
152}
142 153
143 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); 154ResultCode Mutex::Release(VAddr address) {
144 thread->ResumeFromWait(); 155 auto& kernel = system.Kernel();
156 SchedulerLock lock(kernel);
145 157
146 thread->SetLockOwner(nullptr); 158 std::shared_ptr<Thread> current_thread =
147 thread->SetCondVarWaitAddress(0); 159 SharedFrom(kernel.CurrentScheduler().GetCurrentThread());
148 thread->SetMutexWaitAddress(0);
149 thread->SetWaitHandle(0);
150 thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
151 160
152 system.PrepareReschedule(); 161 auto [result, new_owner] = Unlock(current_thread, address);
153 162
154 return RESULT_SUCCESS; 163 if (result != RESULT_SUCCESS && new_owner != nullptr) {
164 new_owner->SetSynchronizationResults(nullptr, result);
165 }
166
167 return result;
155} 168}
169
156} // namespace Kernel 170} // namespace Kernel