synchronization_object.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include "common/assert.h"
  6. #include "common/common_types.h"
  7. #include "common/logging/log.h"
  8. #include "core/core.h"
  9. #include "core/hle/kernel/kernel.h"
  10. #include "core/hle/kernel/object.h"
  11. #include "core/hle/kernel/process.h"
  12. #include "core/hle/kernel/synchronization.h"
  13. #include "core/hle/kernel/synchronization_object.h"
  14. #include "core/hle/kernel/thread.h"
  15. namespace Kernel {
  16. SynchronizationObject::SynchronizationObject(KernelCore& kernel) : Object{kernel} {}
  17. SynchronizationObject::~SynchronizationObject() = default;
  18. void SynchronizationObject::Signal() {
  19. kernel.Synchronization().SignalObject(*this);
  20. }
  21. void SynchronizationObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
  22. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  23. if (itr == waiting_threads.end())
  24. waiting_threads.push_back(std::move(thread));
  25. }
  26. void SynchronizationObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
  27. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  28. // If a thread passed multiple handles to the same object,
  29. // the kernel might attempt to remove the thread from the object's
  30. // waiting threads list multiple times.
  31. if (itr != waiting_threads.end())
  32. waiting_threads.erase(itr);
  33. }
  34. std::shared_ptr<Thread> SynchronizationObject::GetHighestPriorityReadyThread() const {
  35. Thread* candidate = nullptr;
  36. u32 candidate_priority = THREADPRIO_LOWEST + 1;
  37. for (const auto& thread : waiting_threads) {
  38. const ThreadStatus thread_status = thread->GetStatus();
  39. // The list of waiting threads must not contain threads that are not waiting to be awakened.
  40. ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
  41. thread_status == ThreadStatus::WaitHLEEvent,
  42. "Inconsistent thread statuses in waiting_threads");
  43. if (thread->GetPriority() >= candidate_priority)
  44. continue;
  45. if (ShouldWait(thread.get()))
  46. continue;
  47. candidate = thread.get();
  48. candidate_priority = thread->GetPriority();
  49. }
  50. return SharedFrom(candidate);
  51. }
  52. void SynchronizationObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
  53. ASSERT(!ShouldWait(thread.get()));
  54. if (!thread) {
  55. return;
  56. }
  57. if (thread->IsSleepingOnWait()) {
  58. for (const auto& object : thread->GetSynchronizationObjects()) {
  59. ASSERT(!object->ShouldWait(thread.get()));
  60. object->Acquire(thread.get());
  61. }
  62. } else {
  63. Acquire(thread.get());
  64. }
  65. const std::size_t index = thread->GetSynchronizationObjectIndex(SharedFrom(this));
  66. thread->ClearSynchronizationObjects();
  67. thread->CancelWakeupTimer();
  68. bool resume = true;
  69. if (thread->HasWakeupCallback()) {
  70. resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this),
  71. index);
  72. }
  73. if (resume) {
  74. thread->ResumeFromWait();
  75. kernel.PrepareReschedule(thread->GetProcessorID());
  76. }
  77. }
  78. void SynchronizationObject::WakeupAllWaitingThreads() {
  79. while (auto thread = GetHighestPriorityReadyThread()) {
  80. WakeupWaitingThread(thread);
  81. }
  82. }
  83. void SynchronizationObject::ClearWaitingThreads() {
  84. waiting_threads.clear();
  85. }
  86. const std::vector<std::shared_ptr<Thread>>& SynchronizationObject::GetWaitingThreads() const {
  87. return waiting_threads;
  88. }
  89. } // namespace Kernel