summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-05-07 22:29:48 -0400
committerGravatar bunnei2018-05-10 19:34:53 -0400
commitfbd7afefaade8f96defaa5b7353da8933f626917 (patch)
treeb2741ae3c97de21443dbe064f72225a1afbb4e45 /src
parentscheduler: Protect scheduling functions with a global mutex. (diff)
downloadyuzu-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.cpp105
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
157static 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
157void Thread::ResumeFromWait() { 169void 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
420static 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
437void Thread::ChangeCore(u32 core, u64 mask) { 461void 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////////////////////////////////////////////////////////////////////////////////////////////////////