synchronization.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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. if (thread->GetStatus() != ThreadStatus::WaitHLEEvent) {
  23. ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
  24. ASSERT(thread->IsWaitingSync());
  25. }
  26. thread->SetSynchronizationResults(&obj, RESULT_SUCCESS);
  27. thread->ResumeFromWait();
  28. }
  29. }
  30. obj.ClearWaitingThreads();
  31. }
  32. }
  33. std::pair<ResultCode, Handle> Synchronization::WaitFor(
  34. std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
  35. auto& kernel = system.Kernel();
  36. auto* const thread = system.CurrentScheduler().GetCurrentThread();
  37. Handle event_handle = InvalidHandle;
  38. {
  39. SchedulerLockAndSleep lock(kernel, event_handle, thread, nano_seconds);
  40. const auto itr =
  41. std::find_if(sync_objects.begin(), sync_objects.end(),
  42. [thread](const std::shared_ptr<SynchronizationObject>& object) {
  43. return object->IsSignaled();
  44. });
  45. if (itr != sync_objects.end()) {
  46. // We found a ready object, acquire it and set the result value
  47. SynchronizationObject* object = itr->get();
  48. object->Acquire(thread);
  49. const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
  50. lock.CancelSleep();
  51. return {RESULT_SUCCESS, index};
  52. }
  53. if (nano_seconds == 0) {
  54. lock.CancelSleep();
  55. return {RESULT_TIMEOUT, InvalidHandle};
  56. }
  57. if (thread->IsPendingTermination()) {
  58. lock.CancelSleep();
  59. return {ERR_THREAD_TERMINATING, InvalidHandle};
  60. }
  61. if (thread->IsSyncCancelled()) {
  62. thread->SetSyncCancelled(false);
  63. lock.CancelSleep();
  64. return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
  65. }
  66. for (auto& object : sync_objects) {
  67. object->AddWaitingThread(SharedFrom(thread));
  68. }
  69. thread->SetSynchronizationObjects(&sync_objects);
  70. thread->SetSynchronizationResults(nullptr, RESULT_TIMEOUT);
  71. thread->SetStatus(ThreadStatus::WaitSynch);
  72. thread->SetWaitingSync(true);
  73. }
  74. thread->SetWaitingSync(false);
  75. if (event_handle != InvalidHandle) {
  76. auto& time_manager = kernel.TimeManager();
  77. time_manager.UnscheduleTimeEvent(event_handle);
  78. }
  79. {
  80. SchedulerLock lock(kernel);
  81. ResultCode signaling_result = thread->GetSignalingResult();
  82. SynchronizationObject* signaling_object = thread->GetSignalingObject();
  83. thread->SetSynchronizationObjects(nullptr);
  84. auto shared_thread = SharedFrom(thread);
  85. for (auto& obj : sync_objects) {
  86. obj->RemoveWaitingThread(shared_thread);
  87. }
  88. if (signaling_object != nullptr) {
  89. const auto itr = std::find_if(
  90. sync_objects.begin(), sync_objects.end(),
  91. [signaling_object](const std::shared_ptr<SynchronizationObject>& object) {
  92. return object.get() == signaling_object;
  93. });
  94. ASSERT(itr != sync_objects.end());
  95. signaling_object->Acquire(thread);
  96. const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
  97. return {signaling_result, index};
  98. }
  99. return {signaling_result, -1};
  100. }
  101. }
  102. } // namespace Kernel