wait_object.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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/thread.h"
  13. namespace Kernel {
  14. WaitObject::WaitObject(KernelCore& kernel) : Object{kernel} {}
  15. WaitObject::~WaitObject() = default;
  16. void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
  17. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  18. if (itr == waiting_threads.end())
  19. waiting_threads.push_back(std::move(thread));
  20. }
  21. void WaitObject::RemoveWaitingThread(std::shared_ptr<Thread> thread) {
  22. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  23. // If a thread passed multiple handles to the same object,
  24. // the kernel might attempt to remove the thread from the object's
  25. // waiting threads list multiple times.
  26. if (itr != waiting_threads.end())
  27. waiting_threads.erase(itr);
  28. }
  29. std::shared_ptr<Thread> WaitObject::GetHighestPriorityReadyThread() const {
  30. Thread* candidate = nullptr;
  31. u32 candidate_priority = THREADPRIO_LOWEST + 1;
  32. for (const auto& thread : waiting_threads) {
  33. const ThreadStatus thread_status = thread->GetStatus();
  34. // The list of waiting threads must not contain threads that are not waiting to be awakened.
  35. ASSERT_MSG(thread_status == ThreadStatus::WaitSynch ||
  36. thread_status == ThreadStatus::WaitHLEEvent,
  37. "Inconsistent thread statuses in waiting_threads");
  38. if (thread->GetPriority() >= candidate_priority)
  39. continue;
  40. if (ShouldWait(thread.get()))
  41. continue;
  42. candidate = thread.get();
  43. candidate_priority = thread->GetPriority();
  44. }
  45. return SharedFrom(candidate);
  46. }
  47. void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
  48. ASSERT(!ShouldWait(thread.get()));
  49. if (!thread) {
  50. return;
  51. }
  52. if (thread->IsSleepingOnWait()) {
  53. for (const auto& object : thread->GetWaitObjects()) {
  54. ASSERT(!object->ShouldWait(thread.get()));
  55. object->Acquire(thread.get());
  56. }
  57. } else {
  58. Acquire(thread.get());
  59. }
  60. const std::size_t index = thread->GetWaitObjectIndex(SharedFrom(this));
  61. thread->ClearWaitObjects();
  62. thread->CancelWakeupTimer();
  63. bool resume = true;
  64. if (thread->HasWakeupCallback()) {
  65. resume = thread->InvokeWakeupCallback(ThreadWakeupReason::Signal, thread, SharedFrom(this),
  66. index);
  67. }
  68. if (resume) {
  69. thread->ResumeFromWait();
  70. kernel.PrepareReschedule(thread->GetProcessorID());
  71. }
  72. }
  73. void WaitObject::WakeupAllWaitingThreads() {
  74. while (auto thread = GetHighestPriorityReadyThread()) {
  75. WakeupWaitingThread(thread);
  76. }
  77. }
  78. const std::vector<std::shared_ptr<Thread>>& WaitObject::GetWaitingThreads() const {
  79. return waiting_threads;
  80. }
  81. } // namespace Kernel