summaryrefslogtreecommitdiff
path: root/src/core/hle/kernel/svc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
-rw-r--r--src/core/hle/kernel/svc.cpp171
1 files changed, 97 insertions, 74 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 72b5c05f2..1ae530c90 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -401,8 +401,8 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
401 401
402/// Get which CPU core is executing the current thread 402/// Get which CPU core is executing the current thread
403static u32 GetCurrentProcessorNumber() { 403static u32 GetCurrentProcessorNumber() {
404 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, defaulting to processor 0"); 404 NGLOG_TRACE(Kernel_SVC, "called");
405 return 0; 405 return GetCurrentThread()->processor_id;
406} 406}
407 407
408static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size, 408static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 size,
@@ -485,22 +485,28 @@ static void ExitProcess() {
485 485
486 Core::CurrentProcess()->status = ProcessStatus::Exited; 486 Core::CurrentProcess()->status = ProcessStatus::Exited;
487 487
488 // Stop all the process threads that are currently waiting for objects. 488 auto stop_threads = [](const std::vector<SharedPtr<Thread>>& thread_list) {
489 auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList(); 489 for (auto& thread : thread_list) {
490 for (auto& thread : thread_list) { 490 if (thread->owner_process != Core::CurrentProcess())
491 if (thread->owner_process != Core::CurrentProcess()) 491 continue;
492 continue;
493 492
494 if (thread == GetCurrentThread()) 493 if (thread == GetCurrentThread())
495 continue; 494 continue;
496 495
497 // TODO(Subv): When are the other running/ready threads terminated? 496 // TODO(Subv): When are the other running/ready threads terminated?
498 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY || 497 ASSERT_MSG(thread->status == THREADSTATUS_WAIT_SYNCH_ANY ||
499 thread->status == THREADSTATUS_WAIT_SYNCH_ALL, 498 thread->status == THREADSTATUS_WAIT_SYNCH_ALL,
500 "Exiting processes with non-waiting threads is currently unimplemented"); 499 "Exiting processes with non-waiting threads is currently unimplemented");
501 500
502 thread->Stop(); 501 thread->Stop();
503 } 502 }
503 };
504
505 auto& system = Core::System::GetInstance();
506 stop_threads(system.Scheduler(0)->GetThreadList());
507 stop_threads(system.Scheduler(1)->GetThreadList());
508 stop_threads(system.Scheduler(2)->GetThreadList());
509 stop_threads(system.Scheduler(3)->GetThreadList());
504 510
505 // Kill the current thread 511 // Kill the current thread
506 GetCurrentThread()->Stop(); 512 GetCurrentThread()->Stop();
@@ -530,14 +536,9 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
530 536
531 switch (processor_id) { 537 switch (processor_id) {
532 case THREADPROCESSORID_0: 538 case THREADPROCESSORID_0:
533 break;
534 case THREADPROCESSORID_1: 539 case THREADPROCESSORID_1:
535 case THREADPROCESSORID_2: 540 case THREADPROCESSORID_2:
536 case THREADPROCESSORID_3: 541 case THREADPROCESSORID_3:
537 // TODO(bunnei): Implement support for other processor IDs
538 NGLOG_ERROR(Kernel_SVC,
539 "Newly created thread must run in another thread ({}), unimplemented.",
540 processor_id);
541 break; 542 break;
542 default: 543 default:
543 ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id); 544 ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id);
@@ -576,7 +577,7 @@ static ResultCode StartThread(Handle thread_handle) {
576 577
577/// Called when a thread exits 578/// Called when a thread exits
578static void ExitThread() { 579static void ExitThread() {
579 NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CPU().GetPC()); 580 NGLOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", Core::CurrentArmInterface().GetPC());
580 581
581 ExitCurrentThread(); 582 ExitCurrentThread();
582 Core::System::GetInstance().PrepareReschedule(); 583 Core::System::GetInstance().PrepareReschedule();
@@ -588,7 +589,7 @@ static void SleepThread(s64 nanoseconds) {
588 589
589 // Don't attempt to yield execution if there are no available threads to run, 590 // Don't attempt to yield execution if there are no available threads to run,
590 // this way we avoid a useless reschedule to the idle thread. 591 // this way we avoid a useless reschedule to the idle thread.
591 if (nanoseconds == 0 && !Core::System::GetInstance().Scheduler().HaveReadyThreads()) 592 if (nanoseconds == 0 && !Core::System::GetInstance().CurrentScheduler().HaveReadyThreads())
592 return; 593 return;
593 594
594 // Sleep current thread and check for next thread to schedule 595 // Sleep current thread and check for next thread to schedule
@@ -624,7 +625,7 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
624 625
625 // Note: Deliberately don't attempt to inherit the lock owner's priority. 626 // Note: Deliberately don't attempt to inherit the lock owner's priority.
626 627
627 Core::System::GetInstance().PrepareReschedule(); 628 Core::System::GetInstance().CpuCore(current_thread->processor_id).PrepareReschedule();
628 return RESULT_SUCCESS; 629 return RESULT_SUCCESS;
629} 630}
630 631
@@ -634,53 +635,60 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
634 condition_variable_addr, target); 635 condition_variable_addr, target);
635 636
636 u32 processed = 0; 637 u32 processed = 0;
637 auto& thread_list = Core::System::GetInstance().Scheduler().GetThreadList();
638
639 for (auto& thread : thread_list) {
640 if (thread->condvar_wait_address != condition_variable_addr)
641 continue;
642
643 // Only process up to 'target' threads, unless 'target' is -1, in which case process
644 // them all.
645 if (target != -1 && processed >= target)
646 break;
647
648 // If the mutex is not yet acquired, acquire it.
649 u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
650
651 if (mutex_val == 0) {
652 // We were able to acquire the mutex, resume this thread.
653 Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
654 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
655 thread->ResumeFromWait();
656
657 auto lock_owner = thread->lock_owner;
658 if (lock_owner)
659 lock_owner->RemoveMutexWaiter(thread);
660
661 thread->lock_owner = nullptr;
662 thread->mutex_wait_address = 0;
663 thread->condvar_wait_address = 0;
664 thread->wait_handle = 0;
665 } else {
666 // Couldn't acquire the mutex, block the thread.
667 Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
668 auto owner = g_handle_table.Get<Thread>(owner_handle);
669 ASSERT(owner);
670 ASSERT(thread->status != THREADSTATUS_RUNNING);
671 thread->status = THREADSTATUS_WAIT_MUTEX;
672 thread->wakeup_callback = nullptr;
673 638
674 // Signal that the mutex now has a waiting thread. 639 auto signal_process_wide_key = [&](size_t core_index) {
675 Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag); 640 const auto& scheduler = Core::System::GetInstance().Scheduler(core_index);
676 641 for (auto& thread : scheduler->GetThreadList()) {
677 owner->AddMutexWaiter(thread); 642 if (thread->condvar_wait_address != condition_variable_addr)
678 643 continue;
679 Core::System::GetInstance().PrepareReschedule(); 644
645 // Only process up to 'target' threads, unless 'target' is -1, in which case process
646 // them all.
647 if (target != -1 && processed >= target)
648 break;
649
650 // If the mutex is not yet acquired, acquire it.
651 u32 mutex_val = Memory::Read32(thread->mutex_wait_address);
652
653 if (mutex_val == 0) {
654 // We were able to acquire the mutex, resume this thread.
655 Memory::Write32(thread->mutex_wait_address, thread->wait_handle);
656 ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX);
657 thread->ResumeFromWait();
658
659 auto lock_owner = thread->lock_owner;
660 if (lock_owner)
661 lock_owner->RemoveMutexWaiter(thread);
662
663 thread->lock_owner = nullptr;
664 thread->mutex_wait_address = 0;
665 thread->condvar_wait_address = 0;
666 thread->wait_handle = 0;
667 } else {
668 // Couldn't acquire the mutex, block the thread.
669 Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
670 auto owner = g_handle_table.Get<Thread>(owner_handle);
671 ASSERT(owner);
672 ASSERT(thread->status != THREADSTATUS_RUNNING);
673 thread->status = THREADSTATUS_WAIT_MUTEX;
674 thread->wakeup_callback = nullptr;
675
676 // Signal that the mutex now has a waiting thread.
677 Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag);
678
679 owner->AddMutexWaiter(thread);
680
681 Core::System::GetInstance().CpuCore(thread->processor_id).PrepareReschedule();
682 }
683
684 ++processed;
680 } 685 }
686 };
681 687
682 ++processed; 688 signal_process_wide_key(0);
683 } 689 signal_process_wide_key(1);
690 signal_process_wide_key(2);
691 signal_process_wide_key(3);
684 692
685 return RESULT_SUCCESS; 693 return RESULT_SUCCESS;
686} 694}
@@ -718,16 +726,31 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
718 return RESULT_SUCCESS; 726 return RESULT_SUCCESS;
719} 727}
720 728
721static ResultCode GetThreadCoreMask(Handle handle, u32* mask, u64* unknown) { 729static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
722 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}", handle); 730 NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
723 *mask = 0x0; 731
724 *unknown = 0xf; 732 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
733 if (!thread) {
734 return ERR_INVALID_HANDLE;
735 }
736
737 *core = thread->ideal_core;
738 *mask = thread->affinity_mask;
739
725 return RESULT_SUCCESS; 740 return RESULT_SUCCESS;
726} 741}
727 742
728static ResultCode SetThreadCoreMask(Handle handle, u32 mask, u64 unknown) { 743static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
729 NGLOG_WARNING(Kernel_SVC, "(STUBBED) called, handle=0x{:08X}, mask=0x{:08X}, unknown=0x{:X}", 744 NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:08X}, core=0x{:X}", thread_handle,
730 handle, mask, unknown); 745 mask, core);
746
747 const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
748 if (!thread) {
749 return ERR_INVALID_HANDLE;
750 }
751
752 thread->ChangeCore(core, mask);
753
731 return RESULT_SUCCESS; 754 return RESULT_SUCCESS;
732} 755}
733 756