synchronization.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "core/core.h"
  5. #include "core/hle/kernel/errors.h"
  6. #include "core/hle/kernel/handle_table.h"
  7. #include "core/hle/kernel/kernel.h"
  8. #include "core/hle/kernel/scheduler.h"
  9. #include "core/hle/kernel/synchronization.h"
  10. #include "core/hle/kernel/synchronization_object.h"
  11. #include "core/hle/kernel/thread.h"
  12. #include "core/hle/kernel/time_manager.h"
  13. namespace Kernel {
  14. Synchronization::Synchronization(Core::System& system) : system{system} {}
  15. void Synchronization::SignalObject(SynchronizationObject& obj) const {
  16. auto& kernel = system.Kernel();
  17. SchedulerLock lock(kernel);
  18. auto& time_manager = kernel.TimeManager();
  19. if (obj.IsSignaled()) {
  20. for (auto thread : obj.GetWaitingThreads()) {
  21. if (thread->GetSchedulingStatus() == ThreadSchedStatus::Paused) {
  22. ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
  23. ASSERT(thread->IsWaitingSync());
  24. thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
  25. thread->ResumeFromWait();
  26. }
  27. }
  28. obj.ClearWaitingThreads();
  29. }
  30. }
  31. std::pair<ResultCode, Handle> Synchronization::WaitFor(
  32. std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
  33. auto& kernel = system.Kernel();
  34. auto* const thread = system.CurrentScheduler().GetCurrentThread();
  35. Handle event_handle = InvalidHandle;
  36. {
  37. SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
  38. const auto itr =
  39. std::find_if(sync_objects.begin(), sync_objects.end(),
  40. [thread](const std::shared_ptr<SynchronizationObject>& object) {
  41. return object->IsSignaled();
  42. });
  43. if (itr != sync_objects.end()) {
  44. // We found a ready object, acquire it and set the result value
  45. SynchronizationObject* object = itr->get();
  46. object->Acquire(thread);
  47. const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
  48. lock.CancelSleep();
  49. return {RESULT_SUCCESS, index};
  50. }
  51. if (nano_seconds == 0) {
  52. lock.CancelSleep();
  53. return {RESULT_TIMEOUT, InvalidHandle};
  54. }
  55. if (thread->IsPendingTermination()) {
  56. lock.CancelSleep();
  57. return {ERR_THREAD_TERMINATING, InvalidHandle};
  58. }
  59. if (thread->IsSyncCancelled()) {
  60. thread->SetSyncCancelled(false);
  61. lock.CancelSleep();
  62. return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
  63. }
  64. for (auto& object : sync_objects) {
  65. object->AddWaitingThread(SharedFrom(thread));
  66. }
  67. thread->SetSynchronizationObjects(&sync_objects);
  68. thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
  69. thread->SetStatus(ThreadStatus::WaitSynch);
  70. thread->SetWaitingSync(true);
  71. }
  72. thread->SetWaitingSync(false);
  73. if (event_handle != InvalidHandle) {
  74. auto& time_manager = kernel.TimeManager();
  75. time_manager.UnscheduleTimeEvent(event_handle);
  76. }
  77. {
  78. SchedulerLock lock(kernel);
  79. ResultCode signaling_result = thread->GetSignalingResult();
  80. SynchronizationObject* signaling_object = thread->GetSignalingObject();
  81. thread->SetSynchronizationObjects(nullptr);
  82. auto shared_thread = SharedFrom(thread);
  83. for (auto& obj : sync_objects) {
  84. obj->RemoveWaitingThread(shared_thread);
  85. }
  86. if (signaling_object != nullptr) {
  87. const auto itr = std::find_if(
  88. sync_objects.begin(), sync_objects.end(),
  89. [signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
  90. return object.get() == signaling_object;
  91. });
  92. ASSERT(itr != sync_objects.end());
  93. signaling_object->Acquire(thread);
  94. const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
  95. return {signaling_result, index};
  96. }
  97. return {signaling_result, -1};
  98. }
  99. }
  100. } // namespace Kernel