wait_object.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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/logging/log.h"
  7. #include "core/hle/kernel/errors.h"
  8. #include "core/hle/kernel/kernel.h"
  9. #include "core/hle/kernel/memory.h"
  10. #include "core/hle/kernel/process.h"
  11. #include "core/hle/kernel/resource_limit.h"
  12. #include "core/hle/kernel/thread.h"
  13. #include "core/hle/kernel/timer.h"
  14. namespace Kernel {
  15. void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
  16. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  17. if (itr == waiting_threads.end())
  18. waiting_threads.push_back(std::move(thread));
  19. }
  20. void WaitObject::RemoveWaitingThread(Thread* thread) {
  21. auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
  22. // If a thread passed multiple handles to the same object,
  23. // the kernel might attempt to remove the thread from the object's
  24. // waiting threads list multiple times.
  25. if (itr != waiting_threads.end())
  26. waiting_threads.erase(itr);
  27. }
  28. SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
  29. Thread* candidate = nullptr;
  30. u32 candidate_priority = THREADPRIO_LOWEST + 1;
  31. for (const auto& thread : waiting_threads) {
  32. // The list of waiting threads must not contain threads that are not waiting to be awakened.
  33. ASSERT_MSG(thread->status == ThreadStatus::WaitSynchAny ||
  34. thread->status == ThreadStatus::WaitSynchAll ||
  35. thread->status == ThreadStatus::WaitHLEEvent,
  36. "Inconsistent thread statuses in waiting_threads");
  37. if (thread->current_priority >= candidate_priority)
  38. continue;
  39. if (ShouldWait(thread.get()))
  40. continue;
  41. // A thread is ready to run if it's either in ThreadStatus::WaitSynchAny or
  42. // in ThreadStatus::WaitSynchAll and the rest of the objects it is waiting on are ready.
  43. bool ready_to_run = true;
  44. if (thread->status == ThreadStatus::WaitSynchAll) {
  45. ready_to_run = std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
  46. [&thread](const SharedPtr<WaitObject>& object) {
  47. return object->ShouldWait(thread.get());
  48. });
  49. }
  50. if (ready_to_run) {
  51. candidate = thread.get();
  52. candidate_priority = thread->current_priority;
  53. }
  54. }
  55. return candidate;
  56. }
  57. void WaitObject::WakeupWaitingThread(SharedPtr<Thread> thread) {
  58. ASSERT(!ShouldWait(thread.get()));
  59. if (!thread)
  60. return;
  61. if (!thread->IsSleepingOnWaitAll()) {
  62. Acquire(thread.get());
  63. } else {
  64. for (auto& object : thread->wait_objects) {
  65. ASSERT(!object->ShouldWait(thread.get()));
  66. object->Acquire(thread.get());
  67. }
  68. }
  69. size_t index = thread->GetWaitObjectIndex(this);
  70. for (auto& object : thread->wait_objects)
  71. object->RemoveWaitingThread(thread.get());
  72. thread->wait_objects.clear();
  73. thread->CancelWakeupTimer();
  74. bool resume = true;
  75. if (thread->wakeup_callback)
  76. resume = thread->wakeup_callback(ThreadWakeupReason::Signal, thread, this, index);
  77. if (resume)
  78. thread->ResumeFromWait();
  79. }
  80. void WaitObject::WakeupAllWaitingThreads() {
  81. while (auto thread = GetHighestPriorityReadyThread()) {
  82. WakeupWaitingThread(thread);
  83. }
  84. }
  85. const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
  86. return waiting_threads;
  87. }
  88. } // namespace Kernel