diff options
| author | 2018-05-11 12:59:23 -0400 | |
|---|---|---|
| committer | 2018-05-11 12:59:23 -0400 | |
| commit | 1b5c02fc37206bbd33715d2dde6258c3f835581c (patch) | |
| tree | 1c33c66e734ff55228e4293cd2720070cd467080 /src/core/hle/kernel/thread.cpp | |
| parent | Merge pull request #439 from ogniK5377/GetTPCMasks (diff) | |
| parent | core: Add several missing docstrings. (diff) | |
| download | yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.gz yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.xz yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.zip | |
Merge pull request #436 from bunnei/multi-core
Initial support for multi-core
Diffstat (limited to 'src/core/hle/kernel/thread.cpp')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 102 |
1 files changed, 93 insertions, 9 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 1bd5d9ebf..46fcdefb8 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -64,7 +64,7 @@ void Thread::Stop() { | |||
| 64 | // Clean up thread from ready queue | 64 | // Clean up thread from ready queue |
| 65 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) | 65 | // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) |
| 66 | if (status == THREADSTATUS_READY) { | 66 | if (status == THREADSTATUS_READY) { |
| 67 | Core::System::GetInstance().Scheduler().UnscheduleThread(this, current_priority); | 67 | scheduler->UnscheduleThread(this, current_priority); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | status = THREADSTATUS_DEAD; | 70 | status = THREADSTATUS_DEAD; |
| @@ -92,7 +92,7 @@ void WaitCurrentThread_Sleep() { | |||
| 92 | void ExitCurrentThread() { | 92 | void ExitCurrentThread() { |
| 93 | Thread* thread = GetCurrentThread(); | 93 | Thread* thread = GetCurrentThread(); |
| 94 | thread->Stop(); | 94 | thread->Stop(); |
| 95 | Core::System::GetInstance().Scheduler().RemoveThread(thread); | 95 | Core::System::GetInstance().CurrentScheduler().RemoveThread(thread); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | /** | 98 | /** |
| @@ -154,6 +154,18 @@ void Thread::CancelWakeupTimer() { | |||
| 154 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); | 154 | CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | static boost::optional<s32> GetNextProcessorId(u64 mask) { | ||
| 158 | for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { | ||
| 159 | if (mask & (1ULL << index)) { | ||
| 160 | if (!Core::System().GetInstance().Scheduler(index)->GetCurrentThread()) { | ||
| 161 | // Core is enabled and not running any threads, use this one | ||
| 162 | return index; | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | return {}; | ||
| 167 | } | ||
| 168 | |||
| 157 | void Thread::ResumeFromWait() { | 169 | void Thread::ResumeFromWait() { |
| 158 | ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); | 170 | ASSERT_MSG(wait_objects.empty(), "Thread is waking up while waiting for objects"); |
| 159 | 171 | ||
| @@ -188,8 +200,37 @@ void Thread::ResumeFromWait() { | |||
| 188 | wakeup_callback = nullptr; | 200 | wakeup_callback = nullptr; |
| 189 | 201 | ||
| 190 | status = THREADSTATUS_READY; | 202 | status = THREADSTATUS_READY; |
| 191 | Core::System::GetInstance().Scheduler().ScheduleThread(this, current_priority); | 203 | |
| 192 | Core::System::GetInstance().PrepareReschedule(); | 204 | boost::optional<s32> new_processor_id = GetNextProcessorId(affinity_mask); |
| 205 | if (!new_processor_id) { | ||
| 206 | new_processor_id = processor_id; | ||
| 207 | } | ||
| 208 | if (ideal_core != -1 && | ||
| 209 | Core::System().GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { | ||
| 210 | new_processor_id = ideal_core; | ||
| 211 | } | ||
| 212 | |||
| 213 | ASSERT(*new_processor_id < 4); | ||
| 214 | |||
| 215 | // Add thread to new core's scheduler | ||
| 216 | auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id); | ||
| 217 | |||
| 218 | if (*new_processor_id != processor_id) { | ||
| 219 | // Remove thread from previous core's scheduler | ||
| 220 | scheduler->RemoveThread(this); | ||
| 221 | next_scheduler->AddThread(this, current_priority); | ||
| 222 | } | ||
| 223 | |||
| 224 | processor_id = *new_processor_id; | ||
| 225 | |||
| 226 | // If the thread was ready, unschedule from the previous core and schedule on the new core | ||
| 227 | scheduler->UnscheduleThread(this, current_priority); | ||
| 228 | next_scheduler->ScheduleThread(this, current_priority); | ||
| 229 | |||
| 230 | // Change thread's scheduler | ||
| 231 | scheduler = next_scheduler; | ||
| 232 | |||
| 233 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | ||
| 193 | } | 234 | } |
| 194 | 235 | ||
| 195 | /** | 236 | /** |
| @@ -259,8 +300,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 259 | 300 | ||
| 260 | SharedPtr<Thread> thread(new Thread); | 301 | SharedPtr<Thread> thread(new Thread); |
| 261 | 302 | ||
| 262 | Core::System::GetInstance().Scheduler().AddThread(thread, priority); | ||
| 263 | |||
| 264 | thread->thread_id = NewThreadId(); | 303 | thread->thread_id = NewThreadId(); |
| 265 | thread->status = THREADSTATUS_DORMANT; | 304 | thread->status = THREADSTATUS_DORMANT; |
| 266 | thread->entry_point = entry_point; | 305 | thread->entry_point = entry_point; |
| @@ -268,6 +307,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 268 | thread->nominal_priority = thread->current_priority = priority; | 307 | thread->nominal_priority = thread->current_priority = priority; |
| 269 | thread->last_running_ticks = CoreTiming::GetTicks(); | 308 | thread->last_running_ticks = CoreTiming::GetTicks(); |
| 270 | thread->processor_id = processor_id; | 309 | thread->processor_id = processor_id; |
| 310 | thread->ideal_core = processor_id; | ||
| 311 | thread->affinity_mask = 1ULL << processor_id; | ||
| 271 | thread->wait_objects.clear(); | 312 | thread->wait_objects.clear(); |
| 272 | thread->mutex_wait_address = 0; | 313 | thread->mutex_wait_address = 0; |
| 273 | thread->condvar_wait_address = 0; | 314 | thread->condvar_wait_address = 0; |
| @@ -275,6 +316,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 275 | thread->name = std::move(name); | 316 | thread->name = std::move(name); |
| 276 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); | 317 | thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); |
| 277 | thread->owner_process = owner_process; | 318 | thread->owner_process = owner_process; |
| 319 | thread->scheduler = Core::System().GetInstance().Scheduler(processor_id); | ||
| 320 | thread->scheduler->AddThread(thread, priority); | ||
| 278 | 321 | ||
| 279 | // Find the next available TLS index, and mark it as used | 322 | // Find the next available TLS index, and mark it as used |
| 280 | auto& tls_slots = owner_process->tls_slots; | 323 | auto& tls_slots = owner_process->tls_slots; |
| @@ -337,7 +380,7 @@ void Thread::SetPriority(u32 priority) { | |||
| 337 | } | 380 | } |
| 338 | 381 | ||
| 339 | void Thread::BoostPriority(u32 priority) { | 382 | void Thread::BoostPriority(u32 priority) { |
| 340 | Core::System::GetInstance().Scheduler().SetThreadPriority(this, priority); | 383 | scheduler->SetThreadPriority(this, priority); |
| 341 | current_priority = priority; | 384 | current_priority = priority; |
| 342 | } | 385 | } |
| 343 | 386 | ||
| @@ -406,7 +449,7 @@ void Thread::UpdatePriority() { | |||
| 406 | if (new_priority == current_priority) | 449 | if (new_priority == current_priority) |
| 407 | return; | 450 | return; |
| 408 | 451 | ||
| 409 | Core::System::GetInstance().Scheduler().SetThreadPriority(this, new_priority); | 452 | scheduler->SetThreadPriority(this, new_priority); |
| 410 | 453 | ||
| 411 | current_priority = new_priority; | 454 | current_priority = new_priority; |
| 412 | 455 | ||
| @@ -415,13 +458,54 @@ void Thread::UpdatePriority() { | |||
| 415 | lock_owner->UpdatePriority(); | 458 | lock_owner->UpdatePriority(); |
| 416 | } | 459 | } |
| 417 | 460 | ||
| 461 | void Thread::ChangeCore(u32 core, u64 mask) { | ||
| 462 | ideal_core = core; | ||
| 463 | mask = mask; | ||
| 464 | |||
| 465 | if (status != THREADSTATUS_READY) { | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | |||
| 469 | boost::optional<s32> new_processor_id{GetNextProcessorId(mask)}; | ||
| 470 | |||
| 471 | if (!new_processor_id) { | ||
| 472 | new_processor_id = processor_id; | ||
| 473 | } | ||
| 474 | if (ideal_core != -1 && | ||
| 475 | Core::System().GetInstance().Scheduler(ideal_core)->GetCurrentThread() == nullptr) { | ||
| 476 | new_processor_id = ideal_core; | ||
| 477 | } | ||
| 478 | |||
| 479 | ASSERT(new_processor_id < 4); | ||
| 480 | |||
| 481 | // Add thread to new core's scheduler | ||
| 482 | auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id); | ||
| 483 | |||
| 484 | if (*new_processor_id != processor_id) { | ||
| 485 | // Remove thread from previous core's scheduler | ||
| 486 | scheduler->RemoveThread(this); | ||
| 487 | next_scheduler->AddThread(this, current_priority); | ||
| 488 | } | ||
| 489 | |||
| 490 | processor_id = *new_processor_id; | ||
| 491 | |||
| 492 | // If the thread was ready, unschedule from the previous core and schedule on the new core | ||
| 493 | scheduler->UnscheduleThread(this, current_priority); | ||
| 494 | next_scheduler->ScheduleThread(this, current_priority); | ||
| 495 | |||
| 496 | // Change thread's scheduler | ||
| 497 | scheduler = next_scheduler; | ||
| 498 | |||
| 499 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | ||
| 500 | } | ||
| 501 | |||
| 418 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 502 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 419 | 503 | ||
| 420 | /** | 504 | /** |
| 421 | * Gets the current thread | 505 | * Gets the current thread |
| 422 | */ | 506 | */ |
| 423 | Thread* GetCurrentThread() { | 507 | Thread* GetCurrentThread() { |
| 424 | return Core::System::GetInstance().Scheduler().GetCurrentThread(); | 508 | return Core::System::GetInstance().CurrentScheduler().GetCurrentThread(); |
| 425 | } | 509 | } |
| 426 | 510 | ||
| 427 | void ThreadingInit() { | 511 | void ThreadingInit() { |