synchronization.cpp 4.2 KB

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