synchronization.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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. namespace Kernel {
  13. /// Default thread wakeup callback for WaitSynchronization
  14. static bool DefaultThreadWakeupCallback(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
  15. std::shared_ptr<SynchronizationObject> object,
  16. std::size_t index) {
  17. ASSERT(thread->GetStatus() == ThreadStatus::WaitSynch);
  18. if (reason == ThreadWakeupReason::Timeout) {
  19. thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
  20. return true;
  21. }
  22. ASSERT(reason == ThreadWakeupReason::Signal);
  23. thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
  24. thread->SetWaitSynchronizationOutput(static_cast<u32>(index));
  25. return true;
  26. }
  27. Synchronization::Synchronization(Core::System& system) : system{system} {}
  28. void Synchronization::SignalObject(SynchronizationObject& obj) const {
  29. if (obj.IsSignaled()) {
  30. obj.WakeupAllWaitingThreads();
  31. }
  32. }
  33. std::pair<ResultCode, Handle> Synchronization::WaitFor(
  34. std::vector<std::shared_ptr<SynchronizationObject>>& sync_objects, s64 nano_seconds) {
  35. auto* const thread = system.CurrentScheduler().GetCurrentThread();
  36. // Find the first object that is acquirable in the provided list of objects
  37. const auto itr = std::find_if(sync_objects.begin(), sync_objects.end(),
  38. [thread](const std::shared_ptr<SynchronizationObject>& object) {
  39. return object->IsSignaled();
  40. });
  41. if (itr != sync_objects.end()) {
  42. // We found a ready object, acquire it and set the result value
  43. SynchronizationObject* object = itr->get();
  44. object->Acquire(thread);
  45. const u32 index = static_cast<s32>(std::distance(sync_objects.begin(), itr));
  46. return {RESULT_SUCCESS, index};
  47. }
  48. // No objects were ready to be acquired, prepare to suspend the thread.
  49. // If a timeout value of 0 was provided, just return the Timeout error code instead of
  50. // suspending the thread.
  51. if (nano_seconds == 0) {
  52. return {RESULT_TIMEOUT, InvalidHandle};
  53. }
  54. if (thread->IsSyncCancelled()) {
  55. thread->SetSyncCancelled(false);
  56. return {ERR_SYNCHRONIZATION_CANCELED, InvalidHandle};
  57. }
  58. for (auto& object : sync_objects) {
  59. object->AddWaitingThread(SharedFrom(thread));
  60. }
  61. thread->SetSynchronizationObjects(std::move(sync_objects));
  62. thread->SetStatus(ThreadStatus::WaitSynch);
  63. // Create an event to wake the thread up after the specified nanosecond delay has passed
  64. thread->WakeAfterDelay(nano_seconds);
  65. thread->SetWakeupCallback(DefaultThreadWakeupCallback);
  66. system.PrepareReschedule(thread->GetProcessorID());
  67. return {RESULT_TIMEOUT, InvalidHandle};
  68. }
  69. } // namespace Kernel