summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar bunnei2020-12-03 16:43:18 -0800
committerGravatar bunnei2020-12-06 00:03:24 -0800
commit8d3e06349e12e7de17c334619f1f986792d1de4b (patch)
tree926e34570e5e51d5d7dc03c13f45b1401f5ae829 /src/core
parenthle: kernel: Rewrite scheduler implementation based on Mesopshere. (diff)
downloadyuzu-8d3e06349e12e7de17c334619f1f986792d1de4b.tar.gz
yuzu-8d3e06349e12e7de17c334619f1f986792d1de4b.tar.xz
yuzu-8d3e06349e12e7de17c334619f1f986792d1de4b.zip
hle: kernel: Separate KScheduler from GlobalSchedulerContext class.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/kernel/global_scheduler_context.cpp55
-rw-r--r--src/core/hle/kernel/global_scheduler_context.h79
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp48
-rw-r--r--src/core/hle/kernel/k_scheduler.h74
5 files changed, 140 insertions, 118 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 662839ff8..ee61f22c0 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -148,6 +148,8 @@ add_library(core STATIC
148 hle/kernel/code_set.cpp 148 hle/kernel/code_set.cpp
149 hle/kernel/code_set.h 149 hle/kernel/code_set.h
150 hle/kernel/errors.h 150 hle/kernel/errors.h
151 hle/kernel/global_scheduler_context.cpp
152 hle/kernel/global_scheduler_context.h
151 hle/kernel/handle_table.cpp 153 hle/kernel/handle_table.cpp
152 hle/kernel/handle_table.h 154 hle/kernel/handle_table.h
153 hle/kernel/hle_ipc.cpp 155 hle/kernel/hle_ipc.cpp
diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp
new file mode 100644
index 000000000..40e9adf47
--- /dev/null
+++ b/src/core/hle/kernel/global_scheduler_context.cpp
@@ -0,0 +1,55 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <mutex>
6
7#include "common/assert.h"
8#include "core/core.h"
9#include "core/hle/kernel/global_scheduler_context.h"
10#include "core/hle/kernel/k_scheduler.h"
11#include "core/hle/kernel/kernel.h"
12
13namespace Kernel {
14
15GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
16 : kernel{kernel}, scheduler_lock{kernel} {}
17
18GlobalSchedulerContext::~GlobalSchedulerContext() = default;
19
20void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) {
21 std::scoped_lock lock{global_list_guard};
22 thread_list.push_back(std::move(thread));
23}
24
25void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) {
26 std::scoped_lock lock{global_list_guard};
27 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
28 thread_list.end());
29}
30
31void GlobalSchedulerContext::PreemptThreads() {
32 // The priority levels at which the global scheduler preempts threads every 10 ms. They are
33 // ordered from Core 0 to Core 3.
34 std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 63};
35
36 ASSERT(IsLocked());
37 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
38 const u32 priority = preemption_priorities[core_id];
39 kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority);
40 }
41}
42
43bool GlobalSchedulerContext::IsLocked() const {
44 return scheduler_lock.IsLockedByCurrentThread();
45}
46
47void GlobalSchedulerContext::Lock() {
48 scheduler_lock.Lock();
49}
50
51void GlobalSchedulerContext::Unlock() {
52 scheduler_lock.Unlock();
53}
54
55} // namespace Kernel
diff --git a/src/core/hle/kernel/global_scheduler_context.h b/src/core/hle/kernel/global_scheduler_context.h
new file mode 100644
index 000000000..40fe44cc0
--- /dev/null
+++ b/src/core/hle/kernel/global_scheduler_context.h
@@ -0,0 +1,79 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <vector>
9
10#include "common/common_types.h"
11#include "common/spin_lock.h"
12#include "core/hardware_properties.h"
13#include "core/hle/kernel/k_priority_queue.h"
14#include "core/hle/kernel/k_scheduler_lock.h"
15#include "core/hle/kernel/thread.h"
16
17namespace Kernel {
18
19class KernelCore;
20class SchedulerLock;
21
22using KSchedulerPriorityQueue =
23 KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
24static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
25
26class GlobalSchedulerContext final {
27 friend class KScheduler;
28
29public:
30 explicit GlobalSchedulerContext(KernelCore& kernel);
31 ~GlobalSchedulerContext();
32
33 /// Adds a new thread to the scheduler
34 void AddThread(std::shared_ptr<Thread> thread);
35
36 /// Removes a thread from the scheduler
37 void RemoveThread(std::shared_ptr<Thread> thread);
38
39 /// Returns a list of all threads managed by the scheduler
40 const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
41 return thread_list;
42 }
43
44 /**
45 * Rotates the scheduling queues of threads at a preemption priority and then does
46 * some core rebalancing. Preemption priorities can be found in the array
47 * 'preemption_priorities'.
48 *
49 * @note This operation happens every 10ms.
50 */
51 void PreemptThreads();
52
53 /// Returns true if the global scheduler lock is acquired
54 bool IsLocked() const;
55
56private:
57 friend class SchedulerLock;
58
59 /// Lock the scheduler to the current thread.
60 void Lock();
61
62 /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
63 /// and reschedules current core if needed.
64 void Unlock();
65
66 using LockType = KAbstractSchedulerLock<KScheduler>;
67
68 KernelCore& kernel;
69
70 std::atomic_bool scheduler_update_needed{};
71 KSchedulerPriorityQueue priority_queue;
72 LockType scheduler_lock;
73
74 /// Lists all thread ids that aren't deleted/etc.
75 std::vector<std::shared_ptr<Thread>> thread_list;
76 Common::SpinLock global_list_guard{};
77};
78
79} // namespace Kernel
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp
index 7f7da610d..c7e2eabd4 100644
--- a/src/core/hle/kernel/k_scheduler.cpp
+++ b/src/core/hle/kernel/k_scheduler.cpp
@@ -5,12 +5,6 @@
5// This file references various implementation details from Atmosphere, an open-source firmware for 5// This file references various implementation details from Atmosphere, an open-source firmware for
6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. 6// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
7 7
8#include <algorithm>
9#include <mutex>
10#include <set>
11#include <unordered_set>
12#include <utility>
13
14#include "common/assert.h" 8#include "common/assert.h"
15#include "common/bit_util.h" 9#include "common/bit_util.h"
16#include "common/fiber.h" 10#include "common/fiber.h"
@@ -19,10 +13,10 @@
19#include "core/core.h" 13#include "core/core.h"
20#include "core/core_timing.h" 14#include "core/core_timing.h"
21#include "core/cpu_manager.h" 15#include "core/cpu_manager.h"
16#include "core/hle/kernel/k_scheduler.h"
22#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
23#include "core/hle/kernel/physical_core.h" 18#include "core/hle/kernel/physical_core.h"
24#include "core/hle/kernel/process.h" 19#include "core/hle/kernel/process.h"
25#include "core/hle/kernel/k_scheduler.h"
26#include "core/hle/kernel/thread.h" 20#include "core/hle/kernel/thread.h"
27#include "core/hle/kernel/time_manager.h" 21#include "core/hle/kernel/time_manager.h"
28 22
@@ -34,11 +28,6 @@ static void IncrementScheduledCount(Kernel::Thread* thread) {
34 } 28 }
35} 29}
36 30
37GlobalSchedulerContext::GlobalSchedulerContext(KernelCore& kernel)
38 : kernel{kernel}, scheduler_lock{kernel} {}
39
40GlobalSchedulerContext::~GlobalSchedulerContext() = default;
41
42/*static*/ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, 31/*static*/ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule,
43 Core::EmuThreadHandle global_thread) { 32 Core::EmuThreadHandle global_thread) {
44 u32 current_core = global_thread.host_handle; 33 u32 current_core = global_thread.host_handle;
@@ -205,33 +194,6 @@ u64 KScheduler::UpdateHighestPriorityThread(Thread* highest_thread) {
205 return cores_needing_scheduling; 194 return cores_needing_scheduling;
206} 195}
207 196
208void GlobalSchedulerContext::AddThread(std::shared_ptr<Thread> thread) {
209 std::scoped_lock lock{global_list_guard};
210 thread_list.push_back(std::move(thread));
211}
212
213void GlobalSchedulerContext::RemoveThread(std::shared_ptr<Thread> thread) {
214 std::scoped_lock lock{global_list_guard};
215 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
216 thread_list.end());
217}
218
219void GlobalSchedulerContext::PreemptThreads() {
220 // The priority levels at which the global scheduler preempts threads every 10 ms. They are
221 // ordered from Core 0 to Core 3.
222 std::array<u32, Core::Hardware::NUM_CPU_CORES> preemption_priorities = {59, 59, 59, 63};
223
224 ASSERT(IsLocked());
225 for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
226 const u32 priority = preemption_priorities[core_id];
227 kernel.Scheduler(core_id).RotateScheduledQueue(core_id, priority);
228 }
229}
230
231bool GlobalSchedulerContext::IsLocked() const {
232 return scheduler_lock.IsLockedByCurrentThread();
233}
234
235/*static*/ void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread, 197/*static*/ void KScheduler::OnThreadStateChanged(KernelCore& kernel, Thread* thread,
236 u32 old_state) { 198 u32 old_state) {
237 ASSERT(kernel.GlobalSchedulerContext().IsLocked()); 199 ASSERT(kernel.GlobalSchedulerContext().IsLocked());
@@ -635,14 +597,6 @@ void KScheduler::YieldToAnyThread() {
635 } 597 }
636} 598}
637 599
638void GlobalSchedulerContext::Lock() {
639 scheduler_lock.Lock();
640}
641
642void GlobalSchedulerContext::Unlock() {
643 scheduler_lock.Unlock();
644}
645
646KScheduler::KScheduler(Core::System& system, std::size_t core_id) 600KScheduler::KScheduler(Core::System& system, std::size_t core_id)
647 : system(system), core_id(core_id) { 601 : system(system), core_id(core_id) {
648 switch_fiber = std::make_shared<Common::Fiber>(std::function<void(void*)>(OnSwitch), this); 602 switch_fiber = std::make_shared<Common::Fiber>(std::function<void(void*)>(OnSwitch), this);
diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h
index 535ee34b9..7f020d96e 100644
--- a/src/core/hle/kernel/k_scheduler.h
+++ b/src/core/hle/kernel/k_scheduler.h
@@ -8,94 +8,27 @@
8#pragma once 8#pragma once
9 9
10#include <atomic> 10#include <atomic>
11#include <memory>
12#include <mutex>
13#include <vector>
14 11
15#include "common/common_types.h" 12#include "common/common_types.h"
16#include "common/multi_level_queue.h"
17#include "common/scope_exit.h"
18#include "common/spin_lock.h" 13#include "common/spin_lock.h"
19#include "core/core_timing.h" 14#include "core/hle/kernel/global_scheduler_context.h"
20#include "core/hardware_properties.h"
21#include "core/hle/kernel/k_priority_queue.h" 15#include "core/hle/kernel/k_priority_queue.h"
22#include "core/hle/kernel/k_scheduler_lock.h" 16#include "core/hle/kernel/k_scheduler_lock.h"
23#include "core/hle/kernel/thread.h"
24 17
25namespace Common { 18namespace Common {
26class Fiber; 19class Fiber;
27} 20}
28 21
29namespace Core { 22namespace Core {
30class ARM_Interface;
31class System; 23class System;
32} // namespace Core 24}
33 25
34namespace Kernel { 26namespace Kernel {
35 27
36class KernelCore; 28class KernelCore;
37class Process; 29class Process;
38class SchedulerLock; 30class SchedulerLock;
39 31class Thread;
40using KSchedulerPriorityQueue =
41 KPriorityQueue<Thread, Core::Hardware::NUM_CPU_CORES, THREADPRIO_LOWEST, THREADPRIO_HIGHEST>;
42static constexpr s32 HighestCoreMigrationAllowedPriority = 2;
43
44class GlobalSchedulerContext final {
45 friend class KScheduler;
46
47public:
48 explicit GlobalSchedulerContext(KernelCore& kernel);
49 ~GlobalSchedulerContext();
50
51 /// Adds a new thread to the scheduler
52 void AddThread(std::shared_ptr<Thread> thread);
53
54 /// Removes a thread from the scheduler
55 void RemoveThread(std::shared_ptr<Thread> thread);
56
57 /// Returns a list of all threads managed by the scheduler
58 const std::vector<std::shared_ptr<Thread>>& GetThreadList() const {
59 return thread_list;
60 }
61
62 /**
63 * Rotates the scheduling queues of threads at a preemption priority and then does
64 * some core rebalancing. Preemption priorities can be found in the array
65 * 'preemption_priorities'.
66 *
67 * @note This operation happens every 10ms.
68 */
69 void PreemptThreads();
70
71 u32 CpuCoresCount() const {
72 return Core::Hardware::NUM_CPU_CORES;
73 }
74
75 bool IsLocked() const;
76
77private:
78 friend class SchedulerLock;
79
80 /// Lock the scheduler to the current thread.
81 void Lock();
82
83 /// Unlocks the scheduler, reselects threads, interrupts cores for rescheduling
84 /// and reschedules current core if needed.
85 void Unlock();
86
87 using LockType = KAbstractSchedulerLock<KScheduler>;
88
89 KernelCore& kernel;
90
91 std::atomic_bool scheduler_update_needed{};
92 KSchedulerPriorityQueue priority_queue;
93 LockType scheduler_lock;
94
95 /// Lists all thread ids that aren't deleted/etc.
96 std::vector<std::shared_ptr<Thread>> thread_list;
97 Common::SpinLock global_list_guard{};
98};
99 32
100class KScheduler final { 33class KScheduler final {
101public: 34public:
@@ -221,7 +154,6 @@ private:
221 154
222 /// Switches the CPU's active thread context to that of the specified thread 155 /// Switches the CPU's active thread context to that of the specified thread
223 void ScheduleImpl(); 156 void ScheduleImpl();
224 void SwitchThread(Thread* next_thread);
225 157
226 /// When a thread wakes up, it must run this through it's new scheduler 158 /// When a thread wakes up, it must run this through it's new scheduler
227 void SwitchContextStep2(); 159 void SwitchContextStep2();