summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/thread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
-rw-r--r--src/core/hle/kernel/thread.cpp232
1 files changed, 96 insertions, 136 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index db7f379ac..8cb3593db 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -9,12 +9,14 @@
9 9
10#include "common/assert.h" 10#include "common/assert.h"
11#include "common/common_types.h" 11#include "common/common_types.h"
12#include "common/fiber.h"
12#include "common/logging/log.h" 13#include "common/logging/log.h"
13#include "common/thread_queue_list.h" 14#include "common/thread_queue_list.h"
14#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
15#include "core/core.h" 16#include "core/core.h"
16#include "core/core_timing.h" 17#include "core/core_timing.h"
17#include "core/core_timing_util.h" 18#include "core/core_timing_util.h"
19#include "core/cpu_manager.h"
18#include "core/hardware_properties.h" 20#include "core/hardware_properties.h"
19#include "core/hle/kernel/errors.h" 21#include "core/hle/kernel/errors.h"
20#include "core/hle/kernel/handle_table.h" 22#include "core/hle/kernel/handle_table.h"
@@ -23,6 +25,7 @@
23#include "core/hle/kernel/process.h" 25#include "core/hle/kernel/process.h"
24#include "core/hle/kernel/scheduler.h" 26#include "core/hle/kernel/scheduler.h"
25#include "core/hle/kernel/thread.h" 27#include "core/hle/kernel/thread.h"
28#include "core/hle/kernel/time_manager.h"
26#include "core/hle/result.h" 29#include "core/hle/result.h"
27#include "core/memory.h" 30#include "core/memory.h"
28 31
@@ -44,6 +47,7 @@ Thread::Thread(KernelCore& kernel) : SynchronizationObject{kernel} {}
44Thread::~Thread() = default; 47Thread::~Thread() = default;
45 48
46void Thread::Stop() { 49void Thread::Stop() {
50 SchedulerLock lock(kernel);
47 // Cancel any outstanding wakeup events for this thread 51 // Cancel any outstanding wakeup events for this thread
48 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(), 52 Core::System::GetInstance().CoreTiming().UnscheduleEvent(kernel.ThreadWakeupCallbackEventType(),
49 global_handle); 53 global_handle);
@@ -71,9 +75,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
71 75
72 // This function might be called from any thread so we have to be cautious and use the 76 // This function might be called from any thread so we have to be cautious and use the
73 // thread-safe version of ScheduleEvent. 77 // thread-safe version of ScheduleEvent.
74 const s64 cycles = Core::Timing::nsToCycles(std::chrono::nanoseconds{nanoseconds});
75 Core::System::GetInstance().CoreTiming().ScheduleEvent( 78 Core::System::GetInstance().CoreTiming().ScheduleEvent(
76 cycles, kernel.ThreadWakeupCallbackEventType(), global_handle); 79 nanoseconds, kernel.ThreadWakeupCallbackEventType(), global_handle);
77} 80}
78 81
79void Thread::CancelWakeupTimer() { 82void Thread::CancelWakeupTimer() {
@@ -125,6 +128,16 @@ void Thread::ResumeFromWait() {
125 SetStatus(ThreadStatus::Ready); 128 SetStatus(ThreadStatus::Ready);
126} 129}
127 130
131void Thread::OnWakeUp() {
132 SchedulerLock lock(kernel);
133 if (activity == ThreadActivity::Paused) {
134 SetStatus(ThreadStatus::Paused);
135 return;
136 }
137
138 SetStatus(ThreadStatus::Ready);
139}
140
128void Thread::CancelWait() { 141void Thread::CancelWait() {
129 if (GetSchedulingStatus() != ThreadSchedStatus::Paused) { 142 if (GetSchedulingStatus() != ThreadSchedStatus::Paused) {
130 is_sync_cancelled = true; 143 is_sync_cancelled = true;
@@ -153,12 +166,29 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context,
153 context.fpcr = 0; 166 context.fpcr = 0;
154} 167}
155 168
156ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::string name, 169std::shared_ptr<Common::Fiber> Thread::GetHostContext() const {
157 VAddr entry_point, u32 priority, u64 arg, 170 return host_context;
158 s32 processor_id, VAddr stack_top, 171}
159 Process& owner_process) { 172
173ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadType type_flags,
174 std::string name, VAddr entry_point, u32 priority,
175 u64 arg, s32 processor_id, VAddr stack_top,
176 Process* owner_process) {
177 std::function<void(void*)> init_func = system.GetCpuManager().GetGuestThreadStartFunc();
178 void* init_func_parameter = system.GetCpuManager().GetStartFuncParamater();
179 return Create(system, type_flags, name, entry_point, priority, arg, processor_id, stack_top,
180 owner_process, std::move(init_func), init_func_parameter);
181}
182
183ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadType type_flags,
184 std::string name, VAddr entry_point, u32 priority,
185 u64 arg, s32 processor_id, VAddr stack_top,
186 Process* owner_process,
187 std::function<void(void*)>&& thread_start_func,
188 void* thread_start_parameter) {
189 auto& kernel = system.Kernel();
160 // Check if priority is in ranged. Lowest priority -> highest priority id. 190 // Check if priority is in ranged. Lowest priority -> highest priority id.
161 if (priority > THREADPRIO_LOWEST) { 191 if (priority > THREADPRIO_LOWEST && (type_flags & THREADTYPE_IDLE == 0)) {
162 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority); 192 LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
163 return ERR_INVALID_THREAD_PRIORITY; 193 return ERR_INVALID_THREAD_PRIORITY;
164 } 194 }
@@ -168,11 +198,12 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
168 return ERR_INVALID_PROCESSOR_ID; 198 return ERR_INVALID_PROCESSOR_ID;
169 } 199 }
170 200
171 auto& system = Core::System::GetInstance(); 201 if (owner_process) {
172 if (!system.Memory().IsValidVirtualAddress(owner_process, entry_point)) { 202 if (!system.Memory().IsValidVirtualAddress(*owner_process, entry_point)) {
173 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point); 203 LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:016X}", name, entry_point);
174 // TODO (bunnei): Find the correct error code to use here 204 // TODO (bunnei): Find the correct error code to use here
175 return RESULT_UNKNOWN; 205 return RESULT_UNKNOWN;
206 }
176 } 207 }
177 208
178 std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel); 209 std::shared_ptr<Thread> thread = std::make_shared<Thread>(kernel);
@@ -183,7 +214,7 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
183 thread->stack_top = stack_top; 214 thread->stack_top = stack_top;
184 thread->tpidr_el0 = 0; 215 thread->tpidr_el0 = 0;
185 thread->nominal_priority = thread->current_priority = priority; 216 thread->nominal_priority = thread->current_priority = priority;
186 thread->last_running_ticks = system.CoreTiming().GetTicks(); 217 thread->last_running_ticks = 0;
187 thread->processor_id = processor_id; 218 thread->processor_id = processor_id;
188 thread->ideal_core = processor_id; 219 thread->ideal_core = processor_id;
189 thread->affinity_mask = 1ULL << processor_id; 220 thread->affinity_mask = 1ULL << processor_id;
@@ -193,16 +224,27 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(KernelCore& kernel, std::strin
193 thread->wait_handle = 0; 224 thread->wait_handle = 0;
194 thread->name = std::move(name); 225 thread->name = std::move(name);
195 thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap(); 226 thread->global_handle = kernel.GlobalHandleTable().Create(thread).Unwrap();
196 thread->owner_process = &owner_process; 227 thread->owner_process = owner_process;
197 auto& scheduler = kernel.GlobalScheduler(); 228 thread->type = type_flags;
198 scheduler.AddThread(thread); 229 if ((type_flags & THREADTYPE_IDLE) == 0) {
199 thread->tls_address = thread->owner_process->CreateTLSRegion(); 230 auto& scheduler = kernel.GlobalScheduler();
200 231 scheduler.AddThread(thread);
201 thread->owner_process->RegisterThread(thread.get()); 232 }
202 233 if (owner_process) {
203 ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top), 234 thread->tls_address = thread->owner_process->CreateTLSRegion();
204 static_cast<u32>(entry_point), static_cast<u32>(arg)); 235 thread->owner_process->RegisterThread(thread.get());
205 ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); 236 } else {
237 thread->tls_address = 0;
238 }
239 // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
240 // to initialize the context
241 if ((type_flags & THREADTYPE_HLE) == 0) {
242 ResetThreadContext32(thread->context_32, static_cast<u32>(stack_top),
243 static_cast<u32>(entry_point), static_cast<u32>(arg));
244 ResetThreadContext64(thread->context_64, stack_top, entry_point, arg);
245 }
246 thread->host_context =
247 std::make_shared<Common::Fiber>(std::move(thread_start_func), thread_start_parameter);
206 248
207 return MakeResult<std::shared_ptr<Thread>>(std::move(thread)); 249 return MakeResult<std::shared_ptr<Thread>>(std::move(thread));
208} 250}
@@ -258,7 +300,7 @@ void Thread::SetStatus(ThreadStatus new_status) {
258 } 300 }
259 301
260 if (status == ThreadStatus::Running) { 302 if (status == ThreadStatus::Running) {
261 last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks(); 303 last_running_ticks = Core::System::GetInstance().CoreTiming().GetCPUTicks();
262 } 304 }
263 305
264 status = new_status; 306 status = new_status;
@@ -375,38 +417,55 @@ void Thread::SetActivity(ThreadActivity value) {
375} 417}
376 418
377void Thread::Sleep(s64 nanoseconds) { 419void Thread::Sleep(s64 nanoseconds) {
378 // Sleep current thread and check for next thread to schedule 420 Handle event_handle{};
379 SetStatus(ThreadStatus::WaitSleep); 421 {
422 SchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
423 SetStatus(ThreadStatus::WaitSleep);
424 }
380 425
381 // Create an event to wake the thread up after the specified nanosecond delay has passed 426 if (event_handle != InvalidHandle) {
382 WakeAfterDelay(nanoseconds); 427 auto& time_manager = kernel.TimeManager();
428 time_manager.UnscheduleTimeEvent(event_handle);
429 }
383} 430}
384 431
385bool Thread::YieldSimple() { 432bool Thread::YieldSimple() {
386 auto& scheduler = kernel.GlobalScheduler(); 433 bool result{};
387 return scheduler.YieldThread(this); 434 {
435 SchedulerLock lock(kernel);
436 result = kernel.GlobalScheduler().YieldThread(this);
437 }
438 return result;
388} 439}
389 440
390bool Thread::YieldAndBalanceLoad() { 441bool Thread::YieldAndBalanceLoad() {
391 auto& scheduler = kernel.GlobalScheduler(); 442 bool result{};
392 return scheduler.YieldThreadAndBalanceLoad(this); 443 {
444 SchedulerLock lock(kernel);
445 result = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this);
446 }
447 return result;
393} 448}
394 449
395bool Thread::YieldAndWaitForLoadBalancing() { 450bool Thread::YieldAndWaitForLoadBalancing() {
396 auto& scheduler = kernel.GlobalScheduler(); 451 bool result{};
397 return scheduler.YieldThreadAndWaitForLoadBalancing(this); 452 {
453 SchedulerLock lock(kernel);
454 result = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this);
455 }
456 return result;
398} 457}
399 458
400void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) { 459void Thread::SetSchedulingStatus(ThreadSchedStatus new_status) {
401 const u32 old_flags = scheduling_state; 460 const u32 old_flags = scheduling_state;
402 scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) | 461 scheduling_state = (scheduling_state & static_cast<u32>(ThreadSchedMasks::HighMask)) |
403 static_cast<u32>(new_status); 462 static_cast<u32>(new_status);
404 AdjustSchedulingOnStatus(old_flags); 463 kernel.GlobalScheduler().AdjustSchedulingOnStatus(this, old_flags);
405} 464}
406 465
407void Thread::SetCurrentPriority(u32 new_priority) { 466void Thread::SetCurrentPriority(u32 new_priority) {
408 const u32 old_priority = std::exchange(current_priority, new_priority); 467 const u32 old_priority = std::exchange(current_priority, new_priority);
409 AdjustSchedulingOnPriority(old_priority); 468 kernel.GlobalScheduler().AdjustSchedulingOnPriority(this, old_priority);
410} 469}
411 470
412ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { 471ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
@@ -443,111 +502,12 @@ ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) {
443 processor_id = ideal_core; 502 processor_id = ideal_core;
444 } 503 }
445 } 504 }
446 AdjustSchedulingOnAffinity(old_affinity_mask, old_core); 505 kernel.GlobalScheduler().AdjustSchedulingOnAffinity(this, old_affinity_mask, old_core);
447 } 506 }
448 } 507 }
449 return RESULT_SUCCESS; 508 return RESULT_SUCCESS;
450} 509}
451 510
452void Thread::AdjustSchedulingOnStatus(u32 old_flags) {
453 if (old_flags == scheduling_state) {
454 return;
455 }
456
457 auto& scheduler = kernel.GlobalScheduler();
458 if (static_cast<ThreadSchedStatus>(old_flags & static_cast<u32>(ThreadSchedMasks::LowMask)) ==
459 ThreadSchedStatus::Runnable) {
460 // In this case the thread was running, now it's pausing/exitting
461 if (processor_id >= 0) {
462 scheduler.Unschedule(current_priority, static_cast<u32>(processor_id), this);
463 }
464
465 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
466 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
467 scheduler.Unsuggest(current_priority, core, this);
468 }
469 }
470 } else if (GetSchedulingStatus() == ThreadSchedStatus::Runnable) {
471 // The thread is now set to running from being stopped
472 if (processor_id >= 0) {
473 scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this);
474 }
475
476 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
477 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
478 scheduler.Suggest(current_priority, core, this);
479 }
480 }
481 }
482
483 scheduler.SetReselectionPending();
484}
485
486void Thread::AdjustSchedulingOnPriority(u32 old_priority) {
487 if (GetSchedulingStatus() != ThreadSchedStatus::Runnable) {
488 return;
489 }
490 auto& scheduler = kernel.GlobalScheduler();
491 if (processor_id >= 0) {
492 scheduler.Unschedule(old_priority, static_cast<u32>(processor_id), this);
493 }
494
495 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
496 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
497 scheduler.Unsuggest(old_priority, core, this);
498 }
499 }
500
501 // Add thread to the new priority queues.
502 Thread* current_thread = GetCurrentThread();
503
504 if (processor_id >= 0) {
505 if (current_thread == this) {
506 scheduler.SchedulePrepend(current_priority, static_cast<u32>(processor_id), this);
507 } else {
508 scheduler.Schedule(current_priority, static_cast<u32>(processor_id), this);
509 }
510 }
511
512 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
513 if (core != static_cast<u32>(processor_id) && ((affinity_mask >> core) & 1) != 0) {
514 scheduler.Suggest(current_priority, core, this);
515 }
516 }
517
518 scheduler.SetReselectionPending();
519}
520
521void Thread::AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core) {
522 auto& scheduler = kernel.GlobalScheduler();
523 if (GetSchedulingStatus() != ThreadSchedStatus::Runnable ||
524 current_priority >= THREADPRIO_COUNT) {
525 return;
526 }
527
528 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
529 if (((old_affinity_mask >> core) & 1) != 0) {
530 if (core == static_cast<u32>(old_core)) {
531 scheduler.Unschedule(current_priority, core, this);
532 } else {
533 scheduler.Unsuggest(current_priority, core, this);
534 }
535 }
536 }
537
538 for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
539 if (((affinity_mask >> core) & 1) != 0) {
540 if (core == static_cast<u32>(processor_id)) {
541 scheduler.Schedule(current_priority, core, this);
542 } else {
543 scheduler.Suggest(current_priority, core, this);
544 }
545 }
546 }
547
548 scheduler.SetReselectionPending();
549}
550
551//////////////////////////////////////////////////////////////////////////////////////////////////// 511////////////////////////////////////////////////////////////////////////////////////////////////////
552 512
553/** 513/**