scheduler.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  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 Scheduler final {
  18. public:
  19. explicit Scheduler(Core::System& system, Core::ARM_Interface& cpu_core);
  20. ~Scheduler();
  21. /// Returns whether there are any threads that are ready to run.
  22. bool HaveReadyThreads() const;
  23. /// Reschedules to the next available thread (call after current thread is suspended)
  24. void Reschedule();
  25. /// Gets the current running thread
  26. Thread* GetCurrentThread() const;
  27. /// Gets the timestamp for the last context switch in ticks.
  28. u64 GetLastContextSwitchTicks() const;
  29. /// Adds a new thread to the scheduler
  30. void AddThread(SharedPtr<Thread> thread, u32 priority);
  31. /// Removes a thread from the scheduler
  32. void RemoveThread(Thread* thread);
  33. /// Schedules a thread that has become "ready"
  34. void ScheduleThread(Thread* thread, u32 priority);
  35. /// Unschedules a thread that was already scheduled
  36. void UnscheduleThread(Thread* thread, u32 priority);
  37. /// Sets the priority of a thread in the scheduler
  38. void SetThreadPriority(Thread* thread, u32 priority);
  39. /// Gets the next suggested thread for load balancing
  40. Thread* GetNextSuggestedThread(u32 core, u32 minimum_priority) const;
  41. /**
  42. * YieldWithoutLoadBalancing -- analogous to normal yield on a system
  43. * Moves the thread to the end of the ready queue for its priority, and then reschedules the
  44. * system to the new head of the queue.
  45. *
  46. * Example (Single Core -- but can be extrapolated to multi):
  47. * ready_queue[prio=0]: ThreadA, ThreadB, ThreadC (->exec order->)
  48. * Currently Running: ThreadR
  49. *
  50. * ThreadR calls YieldWithoutLoadBalancing
  51. *
  52. * ThreadR is moved to the end of ready_queue[prio=0]:
  53. * ready_queue[prio=0]: ThreadA, ThreadB, ThreadC, ThreadR (->exec order->)
  54. * Currently Running: Nothing
  55. *
  56. * System is rescheduled (ThreadA is popped off of queue):
  57. * ready_queue[prio=0]: ThreadB, ThreadC, ThreadR (->exec order->)
  58. * Currently Running: ThreadA
  59. *
  60. * If the queue is empty at time of call, no yielding occurs. This does not cross between cores
  61. * or priorities at all.
  62. */
  63. void YieldWithoutLoadBalancing(Thread* thread);
  64. /**
  65. * YieldWithLoadBalancing -- yield but with better selection of the new running thread
  66. * Moves the current thread to the end of the ready queue for its priority, then selects a
  67. * 'suggested thread' (a thread on a different core that could run on this core) from the
  68. * scheduler, changes its core, and reschedules the current core to that thread.
  69. *
  70. * Example (Dual Core -- can be extrapolated to Quad Core, this is just normal yield if it were
  71. * single core):
  72. * ready_queue[core=0][prio=0]: ThreadA, ThreadB (affinities not pictured as irrelevant
  73. * ready_queue[core=1][prio=0]: ThreadC[affinity=both], ThreadD[affinity=core1only]
  74. * Currently Running: ThreadQ on Core 0 || ThreadP on Core 1
  75. *
  76. * ThreadQ calls YieldWithLoadBalancing
  77. *
  78. * ThreadQ is moved to the end of ready_queue[core=0][prio=0]:
  79. * ready_queue[core=0][prio=0]: ThreadA, ThreadB
  80. * ready_queue[core=1][prio=0]: ThreadC[affinity=both], ThreadD[affinity=core1only]
  81. * Currently Running: ThreadQ on Core 0 || ThreadP on Core 1
  82. *
  83. * A list of suggested threads for each core is compiled
  84. * Suggested Threads: {ThreadC on Core 1}
  85. * If this were quad core (as the switch is), there could be between 0 and 3 threads in this
  86. * list. If there are more than one, the thread is selected by highest prio.
  87. *
  88. * ThreadC is core changed to Core 0:
  89. * ready_queue[core=0][prio=0]: ThreadC, ThreadA, ThreadB, ThreadQ
  90. * ready_queue[core=1][prio=0]: ThreadD
  91. * Currently Running: None on Core 0 || ThreadP on Core 1
  92. *
  93. * System is rescheduled (ThreadC is popped off of queue):
  94. * ready_queue[core=0][prio=0]: ThreadA, ThreadB, ThreadQ
  95. * ready_queue[core=1][prio=0]: ThreadD
  96. * Currently Running: ThreadC on Core 0 || ThreadP on Core 1
  97. *
  98. * If no suggested threads can be found this will behave just as normal yield. If there are
  99. * multiple candidates for the suggested thread on a core, the highest prio is taken.
  100. */
  101. void YieldWithLoadBalancing(Thread* thread);
  102. /// Currently unknown -- asserts as unimplemented on call
  103. void YieldAndWaitForLoadBalancing(Thread* thread);
  104. /// Returns a list of all threads managed by the scheduler
  105. const std::vector<SharedPtr<Thread>>& GetThreadList() const {
  106. return thread_list;
  107. }
  108. private:
  109. /**
  110. * Pops and returns the next thread from the thread queue
  111. * @return A pointer to the next ready thread
  112. */
  113. Thread* PopNextReadyThread();
  114. /**
  115. * Switches the CPU's active thread context to that of the specified thread
  116. * @param new_thread The thread to switch to
  117. */
  118. void SwitchContext(Thread* new_thread);
  119. /**
  120. * Called on every context switch to update the internal timestamp
  121. * This also updates the running time ticks for the given thread and
  122. * process using the following difference:
  123. *
  124. * ticks += most_recent_ticks - last_context_switch_ticks
  125. *
  126. * The internal tick timestamp for the scheduler is simply the
  127. * most recent tick count retrieved. No special arithmetic is
  128. * applied to it.
  129. */
  130. void UpdateLastContextSwitchTime(Thread* thread, Process* process);
  131. /// Lists all thread ids that aren't deleted/etc.
  132. std::vector<SharedPtr<Thread>> thread_list;
  133. /// Lists only ready thread ids.
  134. Common::MultiLevelQueue<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
  135. SharedPtr<Thread> current_thread = nullptr;
  136. Core::ARM_Interface& cpu_core;
  137. u64 last_context_switch_time = 0;
  138. Core::System& system;
  139. static std::mutex scheduler_mutex;
  140. };
  141. } // namespace Kernel