wait_object.cpp 3.6 KB

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