summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/multi_level_queue.h22
-rw-r--r--src/core/hle/kernel/scheduler.cpp39
-rw-r--r--src/core/hle/kernel/scheduler.h4
3 files changed, 34 insertions, 31 deletions
diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h
index fc72a8238..d56ab6531 100644
--- a/src/common/multi_level_queue.h
+++ b/src/common/multi_level_queue.h
@@ -107,6 +107,9 @@ public:
107 iterator_impl(const iterator_impl<false>& other) 107 iterator_impl(const iterator_impl<false>& other)
108 : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {} 108 : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
109 109
110 iterator_impl(const iterator_impl<true>& other)
111 : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
112
110 iterator_impl& operator=(const iterator_impl<false>& other) { 113 iterator_impl& operator=(const iterator_impl<false>& other) {
111 mlq = other.mlq; 114 mlq = other.mlq;
112 it = other.it; 115 it = other.it;
@@ -149,7 +152,7 @@ public:
149 using iterator = iterator_impl<false>; 152 using iterator = iterator_impl<false>;
150 using const_iterator = iterator_impl<true>; 153 using const_iterator = iterator_impl<true>;
151 154
152 void add(T& element, u32 priority, bool send_back = true) { 155 void add(const T& element, u32 priority, bool send_back = true) {
153 if (send_back) 156 if (send_back)
154 levels[priority].push_back(element); 157 levels[priority].push_back(element);
155 else 158 else
@@ -158,23 +161,18 @@ public:
158 } 161 }
159 162
160 void remove(const T& element, u32 priority) { 163 void remove(const T& element, u32 priority) {
161 levels[priority].erase(ListIterateTo(levels[priority], element)); 164 auto it = ListIterateTo(levels[priority], element);
165 if (it == levels[priority].end())
166 return;
167 levels[priority].erase(it);
162 if (levels[priority].empty()) { 168 if (levels[priority].empty()) {
163 used_priorities &= ~(1ULL << priority); 169 used_priorities &= ~(1ULL << priority);
164 } 170 }
165 } 171 }
166 172
167 void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) { 173 void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) {
168 const auto new_next = 174 remove(element, old_priority);
169 adjust_front ? levels[new_priority].cbegin() : levels[new_priority].cend(); 175 add(element, new_priority, !adjust_front);
170 ListSplice(levels[new_priority], new_next, levels[old_priority],
171 ListIterateTo(levels[old_priority], element));
172
173 used_priorities |= 1ULL << new_priority;
174
175 if (levels[old_priority].empty()) {
176 used_priorities &= ~(1ULL << old_priority);
177 }
178 } 176 }
179 void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) { 177 void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) {
180 adjust(*it, old_priority, new_priority, adjust_front); 178 adjust(*it, old_priority, new_priority, adjust_front);
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp
index cc189cc64..58217b732 100644
--- a/src/core/hle/kernel/scheduler.cpp
+++ b/src/core/hle/kernel/scheduler.cpp
@@ -30,7 +30,7 @@ Scheduler::~Scheduler() {
30 30
31bool Scheduler::HaveReadyThreads() const { 31bool Scheduler::HaveReadyThreads() const {
32 std::lock_guard<std::mutex> lock(scheduler_mutex); 32 std::lock_guard<std::mutex> lock(scheduler_mutex);
33 return ready_queue.get_first() != nullptr; 33 return !ready_queue.empty();
34} 34}
35 35
36Thread* Scheduler::GetCurrentThread() const { 36Thread* Scheduler::GetCurrentThread() const {
@@ -45,23 +45,27 @@ Thread* Scheduler::PopNextReadyThread() {
45 Thread* next = nullptr; 45 Thread* next = nullptr;
46 Thread* thread = GetCurrentThread(); 46 Thread* thread = GetCurrentThread();
47 47
48
48 if (thread && thread->GetStatus() == ThreadStatus::Running) { 49 if (thread && thread->GetStatus() == ThreadStatus::Running) {
50 if (ready_queue.empty())
51 return thread;
49 // We have to do better than the current thread. 52 // We have to do better than the current thread.
50 // This call returns null when that's not possible. 53 // This call returns null when that's not possible.
51 next = ready_queue.pop_first_better(thread->GetPriority()); 54 next = ready_queue.front();
52 if (!next) { 55 if (next == nullptr || next->GetPriority() >= thread->GetPriority()) {
53 // Otherwise just keep going with the current thread
54 next = thread; 56 next = thread;
55 } 57 }
56 } else { 58 } else {
57 next = ready_queue.pop_first(); 59 if (ready_queue.empty())
60 return nullptr;
61 next = ready_queue.front();
58 } 62 }
59 63
60 return next; 64 return next;
61} 65}
62 66
63void Scheduler::SwitchContext(Thread* new_thread) { 67void Scheduler::SwitchContext(Thread* new_thread) {
64 Thread* const previous_thread = GetCurrentThread(); 68 Thread* previous_thread = GetCurrentThread();
65 Process* const previous_process = system.Kernel().CurrentProcess(); 69 Process* const previous_process = system.Kernel().CurrentProcess();
66 70
67 UpdateLastContextSwitchTime(previous_thread, previous_process); 71 UpdateLastContextSwitchTime(previous_thread, previous_process);
@@ -75,7 +79,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
75 if (previous_thread->GetStatus() == ThreadStatus::Running) { 79 if (previous_thread->GetStatus() == ThreadStatus::Running) {
76 // This is only the case when a reschedule is triggered without the current thread 80 // This is only the case when a reschedule is triggered without the current thread
77 // yielding execution (i.e. an event triggered, system core time-sliced, etc) 81 // yielding execution (i.e. an event triggered, system core time-sliced, etc)
78 ready_queue.push_front(previous_thread->GetPriority(), previous_thread); 82 ready_queue.add(previous_thread, previous_thread->GetPriority(), false);
79 previous_thread->SetStatus(ThreadStatus::Ready); 83 previous_thread->SetStatus(ThreadStatus::Ready);
80 } 84 }
81 } 85 }
@@ -90,7 +94,7 @@ void Scheduler::SwitchContext(Thread* new_thread) {
90 94
91 current_thread = new_thread; 95 current_thread = new_thread;
92 96
93 ready_queue.remove(new_thread->GetPriority(), new_thread); 97 ready_queue.remove(new_thread, new_thread->GetPriority());
94 new_thread->SetStatus(ThreadStatus::Running); 98 new_thread->SetStatus(ThreadStatus::Running);
95 99
96 auto* const thread_owner_process = current_thread->GetOwnerProcess(); 100 auto* const thread_owner_process = current_thread->GetOwnerProcess();
@@ -147,7 +151,6 @@ void Scheduler::AddThread(SharedPtr<Thread> thread, u32 priority) {
147 std::lock_guard<std::mutex> lock(scheduler_mutex); 151 std::lock_guard<std::mutex> lock(scheduler_mutex);
148 152
149 thread_list.push_back(std::move(thread)); 153 thread_list.push_back(std::move(thread));
150 ready_queue.prepare(priority);
151} 154}
152 155
153void Scheduler::RemoveThread(Thread* thread) { 156void Scheduler::RemoveThread(Thread* thread) {
@@ -161,33 +164,35 @@ void Scheduler::ScheduleThread(Thread* thread, u32 priority) {
161 std::lock_guard<std::mutex> lock(scheduler_mutex); 164 std::lock_guard<std::mutex> lock(scheduler_mutex);
162 165
163 ASSERT(thread->GetStatus() == ThreadStatus::Ready); 166 ASSERT(thread->GetStatus() == ThreadStatus::Ready);
164 ready_queue.push_back(priority, thread); 167 ready_queue.add(thread, priority);
165} 168}
166 169
167void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { 170void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
168 std::lock_guard<std::mutex> lock(scheduler_mutex); 171 std::lock_guard<std::mutex> lock(scheduler_mutex);
169 172
170 ASSERT(thread->GetStatus() == ThreadStatus::Ready); 173 ASSERT(thread->GetStatus() == ThreadStatus::Ready);
171 ready_queue.remove(priority, thread); 174 ready_queue.remove(thread, priority);
172} 175}
173 176
174void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { 177void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
175 std::lock_guard<std::mutex> lock(scheduler_mutex); 178 std::lock_guard<std::mutex> lock(scheduler_mutex);
179 if (thread->GetPriority() == priority)
180 return;
176 181
177 // If thread was ready, adjust queues 182 // If thread was ready, adjust queues
178 if (thread->GetStatus() == ThreadStatus::Ready) 183 if (thread->GetStatus() == ThreadStatus::Ready)
179 ready_queue.move(thread, thread->GetPriority(), priority); 184 ready_queue.adjust(thread, thread->GetPriority(), priority);
180 else
181 ready_queue.prepare(priority);
182} 185}
183 186
184Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const { 187Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const {
185 std::lock_guard<std::mutex> lock(scheduler_mutex); 188 std::lock_guard<std::mutex> lock(scheduler_mutex);
186 189
187 const u32 mask = 1U << core; 190 const u32 mask = 1U << core;
188 return ready_queue.get_first_filter([mask, maximum_priority](Thread const* thread) { 191 for (auto& thread : ready_queue) {
189 return (thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority; 192 if ((thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority)
190 }); 193 return thread;
194 }
195 return nullptr;
191} 196}
192 197
193void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { 198void Scheduler::YieldWithoutLoadBalancing(Thread* thread) {
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h
index 1c5bf57d9..44baeb713 100644
--- a/src/core/hle/kernel/scheduler.h
+++ b/src/core/hle/kernel/scheduler.h
@@ -7,7 +7,7 @@
7#include <mutex> 7#include <mutex>
8#include <vector> 8#include <vector>
9#include "common/common_types.h" 9#include "common/common_types.h"
10#include "common/thread_queue_list.h" 10#include "common/multi_level_queue.h"
11#include "core/hle/kernel/object.h" 11#include "core/hle/kernel/object.h"
12#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13 13
@@ -156,7 +156,7 @@ private:
156 std::vector<SharedPtr<Thread>> thread_list; 156 std::vector<SharedPtr<Thread>> thread_list;
157 157
158 /// Lists only ready thread ids. 158 /// Lists only ready thread ids.
159 Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue; 159 Common::MultiLevelQueue<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
160 160
161 SharedPtr<Thread> current_thread = nullptr; 161 SharedPtr<Thread> current_thread = nullptr;
162 162