diff options
| author | 2018-05-07 22:29:48 -0400 | |
|---|---|---|
| committer | 2018-05-10 19:34:53 -0400 | |
| commit | fbd7afefaade8f96defaa5b7353da8933f626917 (patch) | |
| tree | b2741ae3c97de21443dbe064f72225a1afbb4e45 /src | |
| parent | scheduler: Protect scheduling functions with a global mutex. (diff) | |
| download | yuzu-fbd7afefaade8f96defaa5b7353da8933f626917.tar.gz yuzu-fbd7afefaade8f96defaa5b7353da8933f626917.tar.xz yuzu-fbd7afefaade8f96defaa5b7353da8933f626917.zip | |
thread: Support core change on ResumeFromWait and improve ChangeCore.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 105 |
1 files changed, 68 insertions, 37 deletions
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index ac6252eac..04d18dc2f 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -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,7 +200,36 @@ void Thread::ResumeFromWait() { | |||
| 188 | wakeup_callback = nullptr; | 200 | wakeup_callback = nullptr; |
| 189 | 201 | ||
| 190 | status = THREADSTATUS_READY; | 202 | status = THREADSTATUS_READY; |
| 191 | scheduler->ScheduleThread(this, current_priority); | 203 | |
| 204 | boost::optional<s32> new_processor_id = GetNextProcessorId(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 | |||
| 192 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | 233 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); |
| 193 | } | 234 | } |
| 194 | 235 | ||
| @@ -267,7 +308,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 267 | thread->last_running_ticks = CoreTiming::GetTicks(); | 308 | thread->last_running_ticks = CoreTiming::GetTicks(); |
| 268 | thread->processor_id = processor_id; | 309 | thread->processor_id = processor_id; |
| 269 | thread->ideal_core = processor_id; | 310 | thread->ideal_core = processor_id; |
| 270 | thread->mask = 1 << processor_id; | 311 | thread->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; |
| @@ -417,55 +458,45 @@ void Thread::UpdatePriority() { | |||
| 417 | lock_owner->UpdatePriority(); | 458 | lock_owner->UpdatePriority(); |
| 418 | } | 459 | } |
| 419 | 460 | ||
| 420 | static s32 GetNextProcessorId(u64 mask) { | ||
| 421 | s32 processor_id{}; | ||
| 422 | for (s32 index = 0; index < Core::NUM_CPU_CORES; ++index) { | ||
| 423 | if (mask & (1ULL << index)) { | ||
| 424 | if (!Core::System().GetInstance().Scheduler(index)->GetCurrentThread()) { | ||
| 425 | // Core is enabled and not running any threads, use this one | ||
| 426 | return index; | ||
| 427 | } | ||
| 428 | |||
| 429 | // Core is enabled, but running a thread, less ideal | ||
| 430 | processor_id = index; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | return processor_id; | ||
| 435 | } | ||
| 436 | |||
| 437 | void Thread::ChangeCore(u32 core, u64 mask) { | 461 | void Thread::ChangeCore(u32 core, u64 mask) { |
| 438 | const s32 new_processor_id{GetNextProcessorId(mask)}; | 462 | ideal_core = core; |
| 439 | 463 | mask = mask; | |
| 440 | ASSERT(ideal_core == core); // We're not doing anything with this yet, so assert the expected | ||
| 441 | ASSERT(new_processor_id < Core::NUM_CPU_CORES); | ||
| 442 | 464 | ||
| 443 | if (new_processor_id == processor_id) { | 465 | if (status != THREADSTATUS_READY) { |
| 444 | // Already running on ideal core, nothing to do here | ||
| 445 | return; | 466 | return; |
| 446 | } | 467 | } |
| 447 | 468 | ||
| 448 | ASSERT(status != THREADSTATUS_RUNNING); // Unsupported | 469 | boost::optional<s32> new_processor_id{GetNextProcessorId(mask)}; |
| 449 | 470 | ||
| 450 | processor_id = new_processor_id; | 471 | if (!new_processor_id) { |
| 451 | ideal_core = core; | 472 | new_processor_id = processor_id; |
| 452 | mask = mask; | 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); | ||
| 453 | 480 | ||
| 454 | // Add thread to new core's scheduler | 481 | // Add thread to new core's scheduler |
| 455 | auto& next_scheduler = Core::System().GetInstance().Scheduler(new_processor_id); | 482 | auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id); |
| 456 | next_scheduler->AddThread(this, current_priority); | ||
| 457 | 483 | ||
| 458 | if (status == THREADSTATUS_READY) { | 484 | if (*new_processor_id != processor_id) { |
| 459 | // If the thread was ready, unschedule from the previous core and schedule on the new core | 485 | // Remove thread from previous core's scheduler |
| 460 | scheduler->UnscheduleThread(this, current_priority); | 486 | scheduler->RemoveThread(this); |
| 461 | next_scheduler->ScheduleThread(this, current_priority); | 487 | next_scheduler->AddThread(this, current_priority); |
| 462 | } | 488 | } |
| 463 | 489 | ||
| 464 | // Remove thread from previous core's scheduler | 490 | processor_id = *new_processor_id; |
| 465 | scheduler->RemoveThread(this); | 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); | ||
| 466 | 495 | ||
| 467 | // Change thread's scheduler | 496 | // Change thread's scheduler |
| 468 | scheduler = next_scheduler; | 497 | scheduler = next_scheduler; |
| 498 | |||
| 499 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | ||
| 469 | } | 500 | } |
| 470 | 501 | ||
| 471 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 502 | //////////////////////////////////////////////////////////////////////////////////////////////////// |