k_condition_variable.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "core/arm/exclusive_monitor.h"
  5. #include "core/core.h"
  6. #include "core/hle/kernel/k_condition_variable.h"
  7. #include "core/hle/kernel/k_linked_list.h"
  8. #include "core/hle/kernel/k_process.h"
  9. #include "core/hle/kernel/k_scheduler.h"
  10. #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
  11. #include "core/hle/kernel/k_synchronization_object.h"
  12. #include "core/hle/kernel/k_thread.h"
  13. #include "core/hle/kernel/k_thread_queue.h"
  14. #include "core/hle/kernel/kernel.h"
  15. #include "core/hle/kernel/svc_common.h"
  16. #include "core/hle/kernel/svc_results.h"
  17. #include "core/memory.h"
  18. namespace Kernel {
  19. namespace {
  20. bool ReadFromUser(Core::System& system, u32* out, VAddr address) {
  21. *out = system.Memory().Read32(address);
  22. return true;
  23. }
  24. bool WriteToUser(Core::System& system, VAddr address, const u32* p) {
  25. system.Memory().Write32(address, *p);
  26. return true;
  27. }
  28. bool UpdateLockAtomic(Core::System& system, u32* out, VAddr address, u32 if_zero,
  29. u32 new_orr_mask) {
  30. auto& monitor = system.Monitor();
  31. const auto current_core = system.Kernel().CurrentPhysicalCoreIndex();
  32. // Load the value from the address.
  33. const auto expected = monitor.ExclusiveRead32(current_core, address);
  34. // Orr in the new mask.
  35. u32 value = expected | new_orr_mask;
  36. // If the value is zero, use the if_zero value, otherwise use the newly orr'd value.
  37. if (!expected) {
  38. value = if_zero;
  39. }
  40. // Try to store.
  41. if (!monitor.ExclusiveWrite32(current_core, address, value)) {
  42. // If we failed to store, try again.
  43. return UpdateLockAtomic(system, out, address, if_zero, new_orr_mask);
  44. }
  45. // We're done.
  46. *out = expected;
  47. return true;
  48. }
  49. class ThreadQueueImplForKConditionVariableWaitForAddress final : public KThreadQueue {
  50. public:
  51. explicit ThreadQueueImplForKConditionVariableWaitForAddress(KernelCore& kernel_)
  52. : KThreadQueue(kernel_) {}
  53. void CancelWait(KThread* waiting_thread, ResultCode wait_result,
  54. bool cancel_timer_task) override {
  55. // Remove the thread as a waiter from its owner.
  56. waiting_thread->GetLockOwner()->RemoveWaiter(waiting_thread);
  57. // Invoke the base cancel wait handler.
  58. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
  59. }
  60. };
  61. class ThreadQueueImplForKConditionVariableWaitConditionVariable final : public KThreadQueue {
  62. private:
  63. KConditionVariable::ThreadTree* m_tree;
  64. public:
  65. explicit ThreadQueueImplForKConditionVariableWaitConditionVariable(
  66. KernelCore& kernel_, KConditionVariable::ThreadTree* t)
  67. : KThreadQueue(kernel_), m_tree(t) {}
  68. void CancelWait(KThread* waiting_thread, ResultCode wait_result,
  69. bool cancel_timer_task) override {
  70. // Remove the thread as a waiter from its owner.
  71. if (KThread* owner = waiting_thread->GetLockOwner(); owner != nullptr) {
  72. owner->RemoveWaiter(waiting_thread);
  73. }
  74. // If the thread is waiting on a condvar, remove it from the tree.
  75. if (waiting_thread->IsWaitingForConditionVariable()) {
  76. m_tree->erase(m_tree->iterator_to(*waiting_thread));
  77. waiting_thread->ClearConditionVariable();
  78. }
  79. // Invoke the base cancel wait handler.
  80. KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task);
  81. }
  82. };
  83. } // namespace
  84. KConditionVariable::KConditionVariable(Core::System& system_)
  85. : system{system_}, kernel{system.Kernel()} {}
  86. KConditionVariable::~KConditionVariable() = default;
  87. ResultCode KConditionVariable::SignalToAddress(VAddr addr) {
  88. KThread* owner_thread = kernel.CurrentScheduler()->GetCurrentThread();
  89. // Signal the address.
  90. {
  91. KScopedSchedulerLock sl(kernel);
  92. // Remove waiter thread.
  93. s32 num_waiters{};
  94. KThread* next_owner_thread =
  95. owner_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
  96. // Determine the next tag.
  97. u32 next_value{};
  98. if (next_owner_thread != nullptr) {
  99. next_value = next_owner_thread->GetAddressKeyValue();
  100. if (num_waiters > 1) {
  101. next_value |= Svc::HandleWaitMask;
  102. }
  103. // Write the value to userspace.
  104. ResultCode result{ResultSuccess};
  105. if (WriteToUser(system, addr, std::addressof(next_value))) [[likely]] {
  106. result = ResultSuccess;
  107. } else {
  108. result = ResultInvalidCurrentMemory;
  109. }
  110. // Signal the next owner thread.
  111. next_owner_thread->EndWait(result);
  112. return result;
  113. } else {
  114. // Just write the value to userspace.
  115. R_UNLESS(WriteToUser(system, addr, std::addressof(next_value)),
  116. ResultInvalidCurrentMemory);
  117. return ResultSuccess;
  118. }
  119. }
  120. }
  121. ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 value) {
  122. KThread* cur_thread = kernel.CurrentScheduler()->GetCurrentThread();
  123. ThreadQueueImplForKConditionVariableWaitForAddress wait_queue(kernel);
  124. // Wait for the address.
  125. KThread* owner_thread{};
  126. {
  127. KScopedSchedulerLock sl(kernel);
  128. // Check if the thread should terminate.
  129. R_UNLESS(!cur_thread->IsTerminationRequested(), ResultTerminationRequested);
  130. // Read the tag from userspace.
  131. u32 test_tag{};
  132. R_UNLESS(ReadFromUser(system, std::addressof(test_tag), addr), ResultInvalidCurrentMemory);
  133. // If the tag isn't the handle (with wait mask), we're done.
  134. R_SUCCEED_IF(test_tag != (handle | Svc::HandleWaitMask));
  135. // Get the lock owner thread.
  136. owner_thread = kernel.CurrentProcess()
  137. ->GetHandleTable()
  138. .GetObjectWithoutPseudoHandle<KThread>(handle)
  139. .ReleasePointerUnsafe();
  140. R_UNLESS(owner_thread != nullptr, ResultInvalidHandle);
  141. // Update the lock.
  142. cur_thread->SetAddressKey(addr, value);
  143. owner_thread->AddWaiter(cur_thread);
  144. // Begin waiting.
  145. cur_thread->BeginWait(std::addressof(wait_queue));
  146. cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
  147. cur_thread->SetMutexWaitAddressForDebugging(addr);
  148. }
  149. // Close our reference to the owner thread, now that the wait is over.
  150. owner_thread->Close();
  151. // Get the wait result.
  152. return cur_thread->GetWaitResult();
  153. }
  154. void KConditionVariable::SignalImpl(KThread* thread) {
  155. // Check pre-conditions.
  156. ASSERT(kernel.GlobalSchedulerContext().IsLocked());
  157. // Update the tag.
  158. VAddr address = thread->GetAddressKey();
  159. u32 own_tag = thread->GetAddressKeyValue();
  160. u32 prev_tag{};
  161. bool can_access{};
  162. {
  163. // TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
  164. // TODO(bunnei): We should call CanAccessAtomic(..) here.
  165. can_access = true;
  166. if (can_access) [[likely]] {
  167. UpdateLockAtomic(system, std::addressof(prev_tag), address, own_tag,
  168. Svc::HandleWaitMask);
  169. }
  170. }
  171. if (can_access) [[likely]] {
  172. if (prev_tag == Svc::InvalidHandle) {
  173. // If nobody held the lock previously, we're all good.
  174. thread->EndWait(ResultSuccess);
  175. } else {
  176. // Get the previous owner.
  177. KThread* owner_thread = kernel.CurrentProcess()
  178. ->GetHandleTable()
  179. .GetObjectWithoutPseudoHandle<KThread>(
  180. static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
  181. .ReleasePointerUnsafe();
  182. if (owner_thread) [[likely]] {
  183. // Add the thread as a waiter on the owner.
  184. owner_thread->AddWaiter(thread);
  185. owner_thread->Close();
  186. } else {
  187. // The lock was tagged with a thread that doesn't exist.
  188. thread->EndWait(ResultInvalidState);
  189. }
  190. }
  191. } else {
  192. // If the address wasn't accessible, note so.
  193. thread->EndWait(ResultInvalidCurrentMemory);
  194. }
  195. }
  196. void KConditionVariable::Signal(u64 cv_key, s32 count) {
  197. // Perform signaling.
  198. s32 num_waiters{};
  199. {
  200. KScopedSchedulerLock sl(kernel);
  201. auto it = thread_tree.nfind_light({cv_key, -1});
  202. while ((it != thread_tree.end()) && (count <= 0 || num_waiters < count) &&
  203. (it->GetConditionVariableKey() == cv_key)) {
  204. KThread* target_thread = std::addressof(*it);
  205. this->SignalImpl(target_thread);
  206. it = thread_tree.erase(it);
  207. target_thread->ClearConditionVariable();
  208. ++num_waiters;
  209. }
  210. // If we have no waiters, clear the has waiter flag.
  211. if (it == thread_tree.end() || it->GetConditionVariableKey() != cv_key) {
  212. const u32 has_waiter_flag{};
  213. WriteToUser(system, cv_key, std::addressof(has_waiter_flag));
  214. }
  215. }
  216. }
  217. ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) {
  218. // Prepare to wait.
  219. KThread* cur_thread = GetCurrentThreadPointer(kernel);
  220. ThreadQueueImplForKConditionVariableWaitConditionVariable wait_queue(
  221. kernel, std::addressof(thread_tree));
  222. {
  223. KScopedSchedulerLockAndSleep slp(kernel, cur_thread, timeout);
  224. // Check that the thread isn't terminating.
  225. if (cur_thread->IsTerminationRequested()) {
  226. slp.CancelSleep();
  227. return ResultTerminationRequested;
  228. }
  229. // Update the value and process for the next owner.
  230. {
  231. // Remove waiter thread.
  232. s32 num_waiters{};
  233. KThread* next_owner_thread =
  234. cur_thread->RemoveWaiterByKey(std::addressof(num_waiters), addr);
  235. // Update for the next owner thread.
  236. u32 next_value{};
  237. if (next_owner_thread != nullptr) {
  238. // Get the next tag value.
  239. next_value = next_owner_thread->GetAddressKeyValue();
  240. if (num_waiters > 1) {
  241. next_value |= Svc::HandleWaitMask;
  242. }
  243. // Wake up the next owner.
  244. next_owner_thread->EndWait(ResultSuccess);
  245. }
  246. // Write to the cv key.
  247. {
  248. const u32 has_waiter_flag = 1;
  249. WriteToUser(system, key, std::addressof(has_waiter_flag));
  250. // TODO(bunnei): We should call DataMemoryBarrier(..) here.
  251. }
  252. // Write the value to userspace.
  253. if (!WriteToUser(system, addr, std::addressof(next_value))) {
  254. slp.CancelSleep();
  255. return ResultInvalidCurrentMemory;
  256. }
  257. }
  258. // If timeout is zero, time out.
  259. R_UNLESS(timeout != 0, ResultTimedOut);
  260. // Update condition variable tracking.
  261. cur_thread->SetConditionVariable(std::addressof(thread_tree), addr, key, value);
  262. thread_tree.insert(*cur_thread);
  263. // Begin waiting.
  264. cur_thread->BeginWait(std::addressof(wait_queue));
  265. cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
  266. cur_thread->SetMutexWaitAddressForDebugging(addr);
  267. }
  268. // Get the wait result.
  269. return cur_thread->GetWaitResult();
  270. }
  271. } // namespace Kernel