scheduler.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <mutex>
  6. #include <vector>
  7. #include "common/common_types.h"
  8. #include "common/multi_level_queue.h"
  9. #include "core/hle/kernel/object.h"
  10. #include "core/hle/kernel/thread.h"
  11. namespace Core {
  12. class ARM_Interface;
  13. class System;
  14. } // namespace Core
  15. namespace Kernel {
  16. class Process;
  17. class GlobalScheduler final {
  18. public:
  19. static constexpr u32 NUM_CPU_CORES = 4;
  20. GlobalScheduler() {
  21. reselection_pending = false;
  22. }
  23. ~GlobalScheduler();
  24. /// Adds a new thread to the scheduler
  25. void AddThread(SharedPtr<Thread> thread);
  26. /// Removes a thread from the scheduler
  27. void RemoveThread(Thread* thread);
  28. /// Returns a list of all threads managed by the scheduler
  29. const std::vector<SharedPtr<Thread>>& GetThreadList() const {
  30. return thread_list;
  31. }
  32. void Suggest(u32 priority, u32 core, Thread* thread) {
  33. suggested_queue[core].add(thread, priority);
  34. }
  35. void Unsuggest(u32 priority, u32 core, Thread* thread) {
  36. suggested_queue[core].remove(thread, priority);
  37. }
  38. void Schedule(u32 priority, u32 core, Thread* thread) {
  39. ASSERT_MSG(thread->GetProcessorID() == core,
  40. "Thread must be assigned to this core.");
  41. scheduled_queue[core].add(thread, priority);
  42. }
  43. void SchedulePrepend(u32 priority, u32 core, Thread* thread) {
  44. ASSERT_MSG(thread->GetProcessorID() == core,
  45. "Thread must be assigned to this core.");
  46. scheduled_queue[core].add(thread, priority, false);
  47. }
  48. void Reschedule(u32 priority, u32 core, Thread* thread) {
  49. scheduled_queue[core].remove(thread, priority);
  50. scheduled_queue[core].add(thread, priority);
  51. }
  52. void Unschedule(u32 priority, u32 core, Thread* thread) {
  53. scheduled_queue[core].remove(thread, priority);
  54. }
  55. void TransferToCore(u32 priority, s32 destination_core, Thread* thread) {
  56. bool schedulable = thread->GetPriority() < THREADPRIO_COUNT;
  57. s32 source_core = thread->GetProcessorID();
  58. if (source_core == destination_core || !schedulable)
  59. return;
  60. thread->SetProcessorID(destination_core);
  61. if (source_core >= 0)
  62. Unschedule(priority, source_core, thread);
  63. if (destination_core >= 0) {
  64. Unsuggest(priority, destination_core, thread);
  65. Schedule(priority, destination_core, thread);
  66. }
  67. if (source_core >= 0)
  68. Suggest(priority, source_core, thread);
  69. }
  70. void UnloadThread(s32 core);
  71. void SelectThreads();
  72. void SelectThread(u32 core);
  73. bool HaveReadyThreads(u32 core_id) {
  74. return !scheduled_queue[core_id].empty();
  75. }
  76. void YieldThread(Thread* thread);
  77. void YieldThreadAndBalanceLoad(Thread* thread);
  78. void YieldThreadAndWaitForLoadBalancing(Thread* thread);
  79. u32 CpuCoresCount() const {
  80. return NUM_CPU_CORES;
  81. }
  82. void SetReselectionPending() {
  83. reselection_pending.store(true, std::memory_order_release);
  84. }
  85. bool IsReselectionPending() {
  86. return reselection_pending.load(std::memory_order_acquire);
  87. }
  88. private:
  89. void AskForReselectionOrMarkRedundant(Thread* current_thread, Thread* winner);
  90. static constexpr u32 min_regular_priority = 2;
  91. std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> scheduled_queue;
  92. std::array<Common::MultiLevelQueue<Thread*, THREADPRIO_COUNT>, NUM_CPU_CORES> suggested_queue;
  93. std::atomic<bool> reselection_pending;
  94. /// Lists all thread ids that aren't deleted/etc.
  95. std::vector<SharedPtr<Thread>> thread_list;
  96. };
  97. class Scheduler final {
  98. public:
  99. explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core, const u32 id);
  100. ~Scheduler();
  101. /// Returns whether there are any threads that are ready to run.
  102. bool HaveReadyThreads() const;
  103. /// Reschedules to the next available thread (call after current thread is suspended)
  104. void TryDoContextSwitch();
  105. void UnloadThread();
  106. void SelectThreads();
  107. /// Gets the current running thread
  108. Thread* GetCurrentThread() const;
  109. Thread* GetSelectedThread() const;
  110. /// Gets the timestamp for the last context switch in ticks.
  111. u64 GetLastContextSwitchTicks() const;
  112. bool ContextSwitchPending() const {
  113. return context_switch_pending;
  114. }
  115. private:
  116. friend class GlobalScheduler;
  117. /**
  118. * Switches the CPU's active thread context to that of the specified thread
  119. * @param new_thread The thread to switch to
  120. */
  121. void SwitchContext();
  122. /**
  123. * Called on every context switch to update the internal timestamp
  124. * This also updates the running time ticks for the given thread and
  125. * process using the following difference:
  126. *
  127. * ticks += most_recent_ticks - last_context_switch_ticks
  128. *
  129. * The internal tick timestamp for the scheduler is simply the
  130. * most recent tick count retrieved. No special arithmetic is
  131. * applied to it.
  132. */
  133. void UpdateLastContextSwitchTime(Thread* thread, Process* process);
  134. SharedPtr<Thread> current_thread = nullptr;
  135. SharedPtr<Thread> selected_thread = nullptr;
  136. Core::System& system;
  137. Core::ARM_Interface& cpu_core;
  138. u64 last_context_switch_time = 0;
  139. u64 idle_selection_count = 0;
  140. const u32 id;
  141. bool context_switch_pending = false;
  142. };
  143. } // namespace Kernel