diff options
| author | 2018-05-05 22:00:34 -0400 | |
|---|---|---|
| committer | 2018-05-10 19:34:49 -0400 | |
| commit | 1c36f2a798372b6bfc54e0e8bd6cf073bed83e6a (patch) | |
| tree | 742fc5f84ee282645bed1b223237cb13146c1447 /src/core/hle/kernel/svc.cpp | |
| parent | svc: Implement GetCurrentProcessorNumber. (diff) | |
| download | yuzu-1c36f2a798372b6bfc54e0e8bd6cf073bed83e6a.tar.gz yuzu-1c36f2a798372b6bfc54e0e8bd6cf073bed83e6a.tar.xz yuzu-1c36f2a798372b6bfc54e0e8bd6cf073bed83e6a.zip | |
svc: SignalProcessWideKey should apply to all cores.
Diffstat (limited to 'src/core/hle/kernel/svc.cpp')
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 93 |
1 files changed, 50 insertions, 43 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index ec32432db..fdf9f9011 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -635,53 +635,60 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target | |||
| 635 | condition_variable_addr, target); | 635 | condition_variable_addr, target); |
| 636 | 636 | ||
| 637 | u32 processed = 0; | 637 | u32 processed = 0; |
| 638 | auto& thread_list = Core::System::GetInstance().CurrentScheduler().GetThreadList(); | ||
| 639 | |||
| 640 | for (auto& thread : thread_list) { | ||
| 641 | if (thread->condvar_wait_address != condition_variable_addr) | ||
| 642 | continue; | ||
| 643 | |||
| 644 | // Only process up to 'target' threads, unless 'target' is -1, in which case process | ||
| 645 | // them all. | ||
| 646 | if (target != -1 && processed >= target) | ||
| 647 | break; | ||
| 648 | |||
| 649 | // If the mutex is not yet acquired, acquire it. | ||
| 650 | u32 mutex_val = Memory::Read32(thread->mutex_wait_address); | ||
| 651 | |||
| 652 | if (mutex_val == 0) { | ||
| 653 | // We were able to acquire the mutex, resume this thread. | ||
| 654 | Memory::Write32(thread->mutex_wait_address, thread->wait_handle); | ||
| 655 | ASSERT(thread->status == THREADSTATUS_WAIT_MUTEX); | ||
| 656 | thread->ResumeFromWait(); | ||
| 657 | |||
| 658 | auto lock_owner = thread->lock_owner; | ||
| 659 | if (lock_owner) | ||
| 660 | lock_owner->RemoveMutexWaiter(thread); | ||
| 661 | |||
| 662 | thread->lock_owner = nullptr; | ||
| 663 | thread->mutex_wait_address = 0; | ||
| 664 | thread->condvar_wait_address = 0; | ||
| 665 | thread->wait_handle = 0; | ||
| 666 | } else { | ||
| 667 | // Couldn't acquire the mutex, block the thread. | ||
| 668 | Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); | ||
| 669 | auto owner = g_handle_table.Get<Thread>(owner_handle); | ||
| 670 | ASSERT(owner); | ||
| 671 | ASSERT(thread->status != THREADSTATUS_RUNNING); | ||
| 672 | thread->status = THREADSTATUS_WAIT_MUTEX; | ||
| 673 | thread->wakeup_callback = nullptr; | ||
| 674 | |||
| 675 | // Signal that the mutex now has a waiting thread. | ||
| 676 | Memory::Write32(thread->mutex_wait_address, mutex_val | Mutex::MutexHasWaitersFlag); | ||
| 677 | 638 | ||
| 678 | owner->AddMutexWaiter(thread); | 639 | auto signal_process_wide_key = [&](size_t core_index) { |
| 640 | const auto& scheduler = Core::System::GetInstance().Scheduler(core_index); | ||
| 641 | for (auto& thread : scheduler->GetThreadList()) { | ||
| 642 | if (thread->condvar_wait_address != condition_variable_addr) | ||
| 643 | continue; | ||
| 679 | 644 | ||
| 680 | Core::System::GetInstance().PrepareReschedule(); | 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().PrepareReschedule(); | ||
| 682 | } | ||
| 683 | |||
| 684 | ++processed; | ||
| 681 | } | 685 | } |
| 686 | }; | ||
| 682 | 687 | ||
| 683 | ++processed; | 688 | signal_process_wide_key(0); |
| 684 | } | 689 | signal_process_wide_key(1); |
| 690 | signal_process_wide_key(2); | ||
| 691 | signal_process_wide_key(3); | ||
| 685 | 692 | ||
| 686 | return RESULT_SUCCESS; | 693 | return RESULT_SUCCESS; |
| 687 | } | 694 | } |