summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2018-02-18 15:17:16 -0500
committerGravatar bunnei2018-02-18 15:17:16 -0500
commitac81c02ed9401b137e83bece2edd6dee8d0a0af2 (patch)
treef849c805fdb9ac756ece2e2f72d6009c58676bd6 /src/core/hle/kernel/thread.cpp
parentkernel: Add Scheduler, which encapsulates the scheduling loading from Thread ... (diff)
downloadyuzu-ac81c02ed9401b137e83bece2edd6dee8d0a0af2.tar.gz
yuzu-ac81c02ed9401b137e83bece2edd6dee8d0a0af2.tar.xz
yuzu-ac81c02ed9401b137e83bece2edd6dee8d0a0af2.zip
kernel: Use Scheduler class for threading.
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp169
1 files changed, 14 insertions, 155 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 0fcc65cbf..dd0a8ae48 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -41,14 +41,6 @@ void Thread::Acquire(Thread* thread) {
41// us to simply use a pool index or similar. 41// us to simply use a pool index or similar.
42static Kernel::HandleTable wakeup_callback_handle_table; 42static Kernel::HandleTable wakeup_callback_handle_table;
43 43
44// Lists all thread ids that aren't deleted/etc.
45static std::vector<SharedPtr<Thread>> thread_list;
46
47// Lists only ready thread ids.
48static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
49
50static SharedPtr<Thread> current_thread;
51
52// The first available thread id at startup 44// The first available thread id at startup
53static u32 next_thread_id; 45static u32 next_thread_id;
54 46
@@ -63,10 +55,6 @@ inline static u32 const NewThreadId() {
63Thread::Thread() {} 55Thread::Thread() {}
64Thread::~Thread() {} 56Thread::~Thread() {}
65 57
66Thread* GetCurrentThread() {
67 return current_thread.get();
68}
69
70/** 58/**
71 * Check if the specified thread is waiting on the specified address to be arbitrated 59 * Check if the specified thread is waiting on the specified address to be arbitrated
72 * @param thread The thread to test 60 * @param thread The thread to test
@@ -86,7 +74,7 @@ void Thread::Stop() {
86 // Clean up thread from ready queue 74 // Clean up thread from ready queue
87 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) 75 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
88 if (status == THREADSTATUS_READY) { 76 if (status == THREADSTATUS_READY) {
89 ready_queue.remove(current_priority, this); 77 Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority);
90 } 78 }
91 79
92 status = THREADSTATUS_DEAD; 80 status = THREADSTATUS_DEAD;
@@ -109,78 +97,6 @@ void Thread::Stop() {
109 Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot); 97 Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
110} 98}
111 99
112/**
113 * Switches the CPU's active thread context to that of the specified thread
114 * @param new_thread The thread to switch to
115 */
116static void SwitchContext(Thread* new_thread) {
117 Thread* previous_thread = GetCurrentThread();
118
119 // Save context for previous thread
120 if (previous_thread) {
121 previous_thread->last_running_ticks = CoreTiming::GetTicks();
122 Core::CPU().SaveContext(previous_thread->context);
123
124 if (previous_thread->status == THREADSTATUS_RUNNING) {
125 // This is only the case when a reschedule is triggered without the current thread
126 // yielding execution (i.e. an event triggered, system core time-sliced, etc)
127 ready_queue.push_front(previous_thread->current_priority, previous_thread);
128 previous_thread->status = THREADSTATUS_READY;
129 }
130 }
131
132 // Load context of new thread
133 if (new_thread) {
134 ASSERT_MSG(new_thread->status == THREADSTATUS_READY,
135 "Thread must be ready to become running.");
136
137 // Cancel any outstanding wakeup events for this thread
138 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
139
140 auto previous_process = Kernel::g_current_process;
141
142 current_thread = new_thread;
143
144 ready_queue.remove(new_thread->current_priority, new_thread);
145 new_thread->status = THREADSTATUS_RUNNING;
146
147 if (previous_process != current_thread->owner_process) {
148 Kernel::g_current_process = current_thread->owner_process;
149 SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
150 }
151
152 Core::CPU().LoadContext(new_thread->context);
153 Core::CPU().SetTlsAddress(new_thread->GetTLSAddress());
154 } else {
155 current_thread = nullptr;
156 // Note: We do not reset the current process and current page table when idling because
157 // technically we haven't changed processes, our threads are just paused.
158 }
159}
160
161/**
162 * Pops and returns the next thread from the thread queue
163 * @return A pointer to the next ready thread
164 */
165static Thread* PopNextReadyThread() {
166 Thread* next;
167 Thread* thread = GetCurrentThread();
168
169 if (thread && thread->status == THREADSTATUS_RUNNING) {
170 // We have to do better than the current thread.
171 // This call returns null when that's not possible.
172 next = ready_queue.pop_first_better(thread->current_priority);
173 if (!next) {
174 // Otherwise just keep going with the current thread
175 next = thread;
176 }
177 } else {
178 next = ready_queue.pop_first();
179 }
180
181 return next;
182}
183
184void WaitCurrentThread_Sleep() { 100void WaitCurrentThread_Sleep() {
185 Thread* thread = GetCurrentThread(); 101 Thread* thread = GetCurrentThread();
186 thread->status = THREADSTATUS_WAIT_SLEEP; 102 thread->status = THREADSTATUS_WAIT_SLEEP;
@@ -195,8 +111,7 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
195void ExitCurrentThread() { 111void ExitCurrentThread() {
196 Thread* thread = GetCurrentThread(); 112 Thread* thread = GetCurrentThread();
197 thread->Stop(); 113 thread->Stop();
198 thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread), 114 Core::System::GetInstance().Scheduler().RemoveThread(thread);
199 thread_list.end());
200} 115}
201 116
202/** 117/**
@@ -274,32 +189,12 @@ void Thread::ResumeFromWait() {
274 189
275 wakeup_callback = nullptr; 190 wakeup_callback = nullptr;
276 191
277 ready_queue.push_back(current_priority, this);
278 status = THREADSTATUS_READY; 192 status = THREADSTATUS_READY;
193 Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority);
279 Core::System::GetInstance().PrepareReschedule(); 194 Core::System::GetInstance().PrepareReschedule();
280} 195}
281 196
282/** 197/**
283 * Prints the thread queue for debugging purposes
284 */
285static void DebugThreadQueue() {
286 Thread* thread = GetCurrentThread();
287 if (!thread) {
288 LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD");
289 } else {
290 LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority,
291 GetCurrentThread()->GetObjectId());
292 }
293
294 for (auto& t : thread_list) {
295 u32 priority = ready_queue.contains(t.get());
296 if (priority != -1) {
297 LOG_DEBUG(Kernel, "0x%02X %u", priority, t->GetObjectId());
298 }
299 }
300}
301
302/**
303 * Finds a free location for the TLS section of a thread. 198 * Finds a free location for the TLS section of a thread.
304 * @param tls_slots The TLS page array of the thread's owner process. 199 * @param tls_slots The TLS page array of the thread's owner process.
305 * Returns a tuple of (page, slot, alloc_needed) where: 200 * Returns a tuple of (page, slot, alloc_needed) where:
@@ -366,8 +261,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
366 261
367 SharedPtr<Thread> thread(new Thread); 262 SharedPtr<Thread> thread(new Thread);
368 263
369 thread_list.push_back(thread); 264 Core::System::GetInstance().Scheduler().AddThread(thread, priority);
370 ready_queue.prepare(priority);
371 265
372 thread->thread_id = NewThreadId(); 266 thread->thread_id = NewThreadId();
373 thread->status = THREADSTATUS_DORMANT; 267 thread->status = THREADSTATUS_DORMANT;
@@ -438,12 +332,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
438void Thread::SetPriority(u32 priority) { 332void Thread::SetPriority(u32 priority) {
439 ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, 333 ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST,
440 "Invalid priority value."); 334 "Invalid priority value.");
441 // If thread was ready, adjust queues 335 Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority);
442 if (status == THREADSTATUS_READY)
443 ready_queue.move(this, current_priority, priority);
444 else
445 ready_queue.prepare(priority);
446
447 nominal_priority = current_priority = priority; 336 nominal_priority = current_priority = priority;
448} 337}
449 338
@@ -457,11 +346,7 @@ void Thread::UpdatePriority() {
457} 346}
458 347
459void Thread::BoostPriority(u32 priority) { 348void Thread::BoostPriority(u32 priority) {
460 // If thread was ready, adjust queues 349 Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority);
461 if (status == THREADSTATUS_READY)
462 ready_queue.move(this, current_priority, priority);
463 else
464 ready_queue.prepare(priority);
465 current_priority = priority; 350 current_priority = priority;
466} 351}
467 352
@@ -487,25 +372,6 @@ SharedPtr<Thread> SetupMainThread(VAddr entry_point, u32 priority,
487 return thread; 372 return thread;
488} 373}
489 374
490bool HaveReadyThreads() {
491 return ready_queue.get_first() != nullptr;
492}
493
494void Reschedule() {
495 Thread* cur = GetCurrentThread();
496 Thread* next = PopNextReadyThread();
497
498 if (cur && next) {
499 LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId());
500 } else if (cur) {
501 LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId());
502 } else if (next) {
503 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
504 }
505
506 SwitchContext(next);
507}
508
509void Thread::SetWaitSynchronizationResult(ResultCode result) { 375void Thread::SetWaitSynchronizationResult(ResultCode result) {
510 context.cpu_registers[0] = result.raw; 376 context.cpu_registers[0] = result.raw;
511} 377}
@@ -528,25 +394,18 @@ VAddr Thread::GetCommandBufferAddress() const {
528 394
529//////////////////////////////////////////////////////////////////////////////////////////////////// 395////////////////////////////////////////////////////////////////////////////////////////////////////
530 396
397/**
398 * Gets the current thread
399 */
400Thread* GetCurrentThread() {
401 return Core::System::GetInstance().Scheduler().GetCurrentThread();
402}
403
531void ThreadingInit() { 404void ThreadingInit() {
532 ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback); 405 ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
533
534 current_thread = nullptr;
535 next_thread_id = 1; 406 next_thread_id = 1;
536} 407}
537 408
538void ThreadingShutdown() { 409void ThreadingShutdown() {}
539 current_thread = nullptr;
540
541 for (auto& t : thread_list) {
542 t->Stop();
543 }
544 thread_list.clear();
545 ready_queue.clear();
546}
547
548const std::vector<SharedPtr<Thread>>& GetThreadList() {
549 return thread_list;
550}
551 410
552} // namespace Kernel 411} // namespace Kernel