diff options
| author | 2021-11-10 22:28:30 -0800 | |
|---|---|---|
| committer | 2021-12-06 16:39:17 -0800 | |
| commit | b0671c7cfaa8bdb9704827af83be9223a5890f97 (patch) | |
| tree | 1cc9ae63853c390166832afe9218257eb0a4ee99 /src/core/hle/kernel | |
| parent | hle: kernel: KConditionVariable: Migrate to updated KThreadQueue. (diff) | |
| download | yuzu-b0671c7cfaa8bdb9704827af83be9223a5890f97.tar.gz yuzu-b0671c7cfaa8bdb9704827af83be9223a5890f97.tar.xz yuzu-b0671c7cfaa8bdb9704827af83be9223a5890f97.zip | |
hle: kernel: KThread: Migrate to updated KThreadQueue (part 1).
Diffstat (limited to 'src/core/hle/kernel')
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 121 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/time_manager.cpp | 6 |
3 files changed, 71 insertions, 60 deletions
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 2c1f29bad..995f0ca50 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -59,6 +59,35 @@ static void ResetThreadContext64(Core::ARM_Interface::ThreadContext64& context, | |||
| 59 | 59 | ||
| 60 | namespace Kernel { | 60 | namespace Kernel { |
| 61 | 61 | ||
| 62 | namespace { | ||
| 63 | |||
| 64 | class ThreadQueueImplForKThreadSleep final : public KThreadQueueWithoutEndWait { | ||
| 65 | public: | ||
| 66 | explicit ThreadQueueImplForKThreadSleep(KernelCore& kernel_) | ||
| 67 | : KThreadQueueWithoutEndWait(kernel_) {} | ||
| 68 | }; | ||
| 69 | |||
| 70 | class ThreadQueueImplForKThreadSetProperty final : public KThreadQueue { | ||
| 71 | private: | ||
| 72 | KThread::WaiterList* m_wait_list; | ||
| 73 | |||
| 74 | public: | ||
| 75 | explicit ThreadQueueImplForKThreadSetProperty(KernelCore& kernel_, KThread::WaiterList* wl) | ||
| 76 | : KThreadQueue(kernel_), m_wait_list(wl) { // ... | ||
| 77 | } | ||
| 78 | |||
| 79 | virtual void CancelWait(KThread* waiting_thread, ResultCode wait_result, | ||
| 80 | bool cancel_timer_task) override { | ||
| 81 | // Remove the thread from the wait list. | ||
| 82 | m_wait_list->erase(m_wait_list->iterator_to(*waiting_thread)); | ||
| 83 | |||
| 84 | // Invoke the base cancel wait handler. | ||
| 85 | KThreadQueue::CancelWait(waiting_thread, wait_result, cancel_timer_task); | ||
| 86 | } | ||
| 87 | }; | ||
| 88 | |||
| 89 | } // namespace | ||
| 90 | |||
| 62 | KThread::KThread(KernelCore& kernel_) | 91 | KThread::KThread(KernelCore& kernel_) |
| 63 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} | 92 | : KAutoObjectWithSlabHeapAndContainer{kernel_}, activity_pause_lock{kernel_} {} |
| 64 | KThread::~KThread() = default; | 93 | KThread::~KThread() = default; |
| @@ -274,11 +303,14 @@ void KThread::Finalize() { | |||
| 274 | 303 | ||
| 275 | auto it = waiter_list.begin(); | 304 | auto it = waiter_list.begin(); |
| 276 | while (it != waiter_list.end()) { | 305 | while (it != waiter_list.end()) { |
| 277 | // The thread shouldn't be a kernel waiter. | 306 | // Clear the lock owner |
| 278 | it->SetLockOwner(nullptr); | 307 | it->SetLockOwner(nullptr); |
| 279 | it->SetWaitResult(ResultInvalidState); | 308 | |
| 280 | it->Wakeup(); | 309 | // Erase the waiter from our list. |
| 281 | it = waiter_list.erase(it); | 310 | it = waiter_list.erase(it); |
| 311 | |||
| 312 | // Cancel the thread's wait. | ||
| 313 | it->CancelWait(ResultInvalidState, true); | ||
| 282 | } | 314 | } |
| 283 | } | 315 | } |
| 284 | 316 | ||
| @@ -295,15 +327,12 @@ bool KThread::IsSignaled() const { | |||
| 295 | return signaled; | 327 | return signaled; |
| 296 | } | 328 | } |
| 297 | 329 | ||
| 298 | void KThread::Wakeup() { | 330 | void KThread::OnTimer() { |
| 299 | KScopedSchedulerLock sl{kernel}; | 331 | ASSERT(kernel.GlobalSchedulerContext().IsLocked()); |
| 300 | 332 | ||
| 333 | // If we're waiting, cancel the wait. | ||
| 301 | if (GetState() == ThreadState::Waiting) { | 334 | if (GetState() == ThreadState::Waiting) { |
| 302 | if (sleeping_queue != nullptr) { | 335 | sleeping_queue->CancelWait(this, ResultTimedOut, false); |
| 303 | sleeping_queue->EndWait(this, ResultSuccess); | ||
| 304 | } else { | ||
| 305 | SetState(ThreadState::Runnable); | ||
| 306 | } | ||
| 307 | } | 336 | } |
| 308 | } | 337 | } |
| 309 | 338 | ||
| @@ -475,7 +504,6 @@ ResultCode KThread::GetPhysicalCoreMask(s32* out_ideal_core, u64* out_affinity_m | |||
| 475 | 504 | ||
| 476 | return ResultSuccess; | 505 | return ResultSuccess; |
| 477 | } | 506 | } |
| 478 | |||
| 479 | ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { | 507 | ResultCode KThread::SetCoreMask(s32 cpu_core_id, u64 v_affinity_mask) { |
| 480 | ASSERT(parent != nullptr); | 508 | ASSERT(parent != nullptr); |
| 481 | ASSERT(v_affinity_mask != 0); | 509 | ASSERT(v_affinity_mask != 0); |
| @@ -642,15 +670,9 @@ void KThread::WaitCancel() { | |||
| 642 | KScopedSchedulerLock sl{kernel}; | 670 | KScopedSchedulerLock sl{kernel}; |
| 643 | 671 | ||
| 644 | // Check if we're waiting and cancellable. | 672 | // Check if we're waiting and cancellable. |
| 645 | if (GetState() == ThreadState::Waiting && cancellable) { | 673 | if (this->GetState() == ThreadState::Waiting && cancellable) { |
| 646 | if (sleeping_queue != nullptr) { | 674 | wait_cancelled = false; |
| 647 | sleeping_queue->WakeupThread(this); | 675 | sleeping_queue->CancelWait(this, ResultCancelled, true); |
| 648 | wait_cancelled = true; | ||
| 649 | } else { | ||
| 650 | SetWaitResult(ResultCancelled); | ||
| 651 | SetState(ThreadState::Runnable); | ||
| 652 | wait_cancelled = false; | ||
| 653 | } | ||
| 654 | } else { | 676 | } else { |
| 655 | // Otherwise, note that we cancelled a wait. | 677 | // Otherwise, note that we cancelled a wait. |
| 656 | wait_cancelled = true; | 678 | wait_cancelled = true; |
| @@ -701,60 +723,59 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { | |||
| 701 | // Set the activity. | 723 | // Set the activity. |
| 702 | { | 724 | { |
| 703 | // Lock the scheduler. | 725 | // Lock the scheduler. |
| 704 | KScopedSchedulerLock sl{kernel}; | 726 | KScopedSchedulerLock sl(kernel); |
| 705 | 727 | ||
| 706 | // Verify our state. | 728 | // Verify our state. |
| 707 | const auto cur_state = GetState(); | 729 | const auto cur_state = this->GetState(); |
| 708 | R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), | 730 | R_UNLESS((cur_state == ThreadState::Waiting || cur_state == ThreadState::Runnable), |
| 709 | ResultInvalidState); | 731 | ResultInvalidState); |
| 710 | 732 | ||
| 711 | // Either pause or resume. | 733 | // Either pause or resume. |
| 712 | if (activity == Svc::ThreadActivity::Paused) { | 734 | if (activity == Svc::ThreadActivity::Paused) { |
| 713 | // Verify that we're not suspended. | 735 | // Verify that we're not suspended. |
| 714 | R_UNLESS(!IsSuspendRequested(SuspendType::Thread), ResultInvalidState); | 736 | R_UNLESS(!this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState); |
| 715 | 737 | ||
| 716 | // Suspend. | 738 | // Suspend. |
| 717 | RequestSuspend(SuspendType::Thread); | 739 | this->RequestSuspend(SuspendType::Thread); |
| 718 | } else { | 740 | } else { |
| 719 | ASSERT(activity == Svc::ThreadActivity::Runnable); | 741 | ASSERT(activity == Svc::ThreadActivity::Runnable); |
| 720 | 742 | ||
| 721 | // Verify that we're suspended. | 743 | // Verify that we're suspended. |
| 722 | R_UNLESS(IsSuspendRequested(SuspendType::Thread), ResultInvalidState); | 744 | R_UNLESS(this->IsSuspendRequested(SuspendType::Thread), ResultInvalidState); |
| 723 | 745 | ||
| 724 | // Resume. | 746 | // Resume. |
| 725 | Resume(SuspendType::Thread); | 747 | this->Resume(SuspendType::Thread); |
| 726 | } | 748 | } |
| 727 | } | 749 | } |
| 728 | 750 | ||
| 729 | // If the thread is now paused, update the pinned waiter list. | 751 | // If the thread is now paused, update the pinned waiter list. |
| 730 | if (activity == Svc::ThreadActivity::Paused) { | 752 | if (activity == Svc::ThreadActivity::Paused) { |
| 731 | bool thread_is_pinned{}; | 753 | ThreadQueueImplForKThreadSetProperty wait_queue_(kernel, |
| 732 | bool thread_is_current{}; | 754 | std::addressof(pinned_waiter_list)); |
| 755 | |||
| 756 | bool thread_is_current; | ||
| 733 | do { | 757 | do { |
| 734 | // Lock the scheduler. | 758 | // Lock the scheduler. |
| 735 | KScopedSchedulerLock sl{kernel}; | 759 | KScopedSchedulerLock sl(kernel); |
| 736 | 760 | ||
| 737 | // Don't do any further management if our termination has been requested. | 761 | // Don't do any further management if our termination has been requested. |
| 738 | R_SUCCEED_IF(IsTerminationRequested()); | 762 | R_SUCCEED_IF(this->IsTerminationRequested()); |
| 763 | |||
| 764 | // By default, treat the thread as not current. | ||
| 765 | thread_is_current = false; | ||
| 739 | 766 | ||
| 740 | // Check whether the thread is pinned. | 767 | // Check whether the thread is pinned. |
| 741 | if (GetStackParameters().is_pinned) { | 768 | if (this->GetStackParameters().is_pinned) { |
| 742 | // Verify that the current thread isn't terminating. | 769 | // Verify that the current thread isn't terminating. |
| 743 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), | 770 | R_UNLESS(!GetCurrentThread(kernel).IsTerminationRequested(), |
| 744 | ResultTerminationRequested); | 771 | ResultTerminationRequested); |
| 745 | 772 | ||
| 746 | // Note that the thread was pinned and not current. | ||
| 747 | thread_is_pinned = true; | ||
| 748 | thread_is_current = false; | ||
| 749 | |||
| 750 | // Wait until the thread isn't pinned any more. | 773 | // Wait until the thread isn't pinned any more. |
| 751 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); | 774 | pinned_waiter_list.push_back(GetCurrentThread(kernel)); |
| 752 | GetCurrentThread(kernel).SetState(ThreadState::Waiting); | 775 | GetCurrentThread(kernel).BeginWait(std::addressof(wait_queue_)); |
| 753 | } else { | 776 | } else { |
| 754 | // Check if the thread is currently running. | 777 | // Check if the thread is currently running. |
| 755 | // If it is, we'll need to retry. | 778 | // If it is, we'll need to retry. |
| 756 | thread_is_current = false; | ||
| 757 | |||
| 758 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { | 779 | for (auto i = 0; i < static_cast<s32>(Core::Hardware::NUM_CPU_CORES); ++i) { |
| 759 | if (kernel.Scheduler(i).GetCurrentThread() == this) { | 780 | if (kernel.Scheduler(i).GetCurrentThread() == this) { |
| 760 | thread_is_current = true; | 781 | thread_is_current = true; |
| @@ -763,16 +784,6 @@ ResultCode KThread::SetActivity(Svc::ThreadActivity activity) { | |||
| 763 | } | 784 | } |
| 764 | } | 785 | } |
| 765 | } while (thread_is_current); | 786 | } while (thread_is_current); |
| 766 | |||
| 767 | // If the thread was pinned, it no longer is, and we should remove the current thread from | ||
| 768 | // our waiter list. | ||
| 769 | if (thread_is_pinned) { | ||
| 770 | // Lock the scheduler. | ||
| 771 | KScopedSchedulerLock sl{kernel}; | ||
| 772 | |||
| 773 | // Remove from the list. | ||
| 774 | pinned_waiter_list.erase(pinned_waiter_list.iterator_to(GetCurrentThread(kernel))); | ||
| 775 | } | ||
| 776 | } | 787 | } |
| 777 | 788 | ||
| 778 | return ResultSuccess; | 789 | return ResultSuccess; |
| @@ -1000,26 +1011,22 @@ ResultCode KThread::Sleep(s64 timeout) { | |||
| 1000 | ASSERT(this == GetCurrentThreadPointer(kernel)); | 1011 | ASSERT(this == GetCurrentThreadPointer(kernel)); |
| 1001 | ASSERT(timeout > 0); | 1012 | ASSERT(timeout > 0); |
| 1002 | 1013 | ||
| 1014 | ThreadQueueImplForKThreadSleep wait_queue(kernel); | ||
| 1003 | { | 1015 | { |
| 1004 | // Setup the scheduling lock and sleep. | 1016 | // Setup the scheduling lock and sleep. |
| 1005 | KScopedSchedulerLockAndSleep slp{kernel, this, timeout}; | 1017 | KScopedSchedulerLockAndSleep slp(kernel, this, timeout); |
| 1006 | 1018 | ||
| 1007 | // Check if the thread should terminate. | 1019 | // Check if the thread should terminate. |
| 1008 | if (IsTerminationRequested()) { | 1020 | if (this->IsTerminationRequested()) { |
| 1009 | slp.CancelSleep(); | 1021 | slp.CancelSleep(); |
| 1010 | return ResultTerminationRequested; | 1022 | return ResultTerminationRequested; |
| 1011 | } | 1023 | } |
| 1012 | 1024 | ||
| 1013 | // Mark the thread as waiting. | 1025 | // Wait for the sleep to end. |
| 1014 | SetState(ThreadState::Waiting); | 1026 | this->BeginWait(std::addressof(wait_queue)); |
| 1015 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); | 1027 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); |
| 1016 | } | 1028 | } |
| 1017 | 1029 | ||
| 1018 | // The lock/sleep is done. | ||
| 1019 | |||
| 1020 | // Cancel the timer. | ||
| 1021 | kernel.TimeManager().UnscheduleTimeEvent(this); | ||
| 1022 | |||
| 1023 | return ResultSuccess; | 1030 | return ResultSuccess; |
| 1024 | } | 1031 | } |
| 1025 | 1032 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index f9a324eb3..6d68c2399 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -161,8 +161,6 @@ public: | |||
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | void Wakeup(); | ||
| 165 | |||
| 166 | void SetBasePriority(s32 value); | 164 | void SetBasePriority(s32 value); |
| 167 | 165 | ||
| 168 | [[nodiscard]] ResultCode Run(); | 166 | [[nodiscard]] ResultCode Run(); |
| @@ -380,6 +378,8 @@ public: | |||
| 380 | 378 | ||
| 381 | [[nodiscard]] bool IsSignaled() const override; | 379 | [[nodiscard]] bool IsSignaled() const override; |
| 382 | 380 | ||
| 381 | void OnTimer(); | ||
| 382 | |||
| 383 | static void PostDestroy(uintptr_t arg); | 383 | static void PostDestroy(uintptr_t arg); |
| 384 | 384 | ||
| 385 | [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); | 385 | [[nodiscard]] static ResultCode InitializeDummyThread(KThread* thread); |
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp index 8cd7279a3..aa985d820 100644 --- a/src/core/hle/kernel/time_manager.cpp +++ b/src/core/hle/kernel/time_manager.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "core/core.h" | 6 | #include "core/core.h" |
| 7 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| 8 | #include "core/hle/kernel/k_scheduler.h" | ||
| 8 | #include "core/hle/kernel/k_thread.h" | 9 | #include "core/hle/kernel/k_thread.h" |
| 9 | #include "core/hle/kernel/time_manager.h" | 10 | #include "core/hle/kernel/time_manager.h" |
| 10 | 11 | ||
| @@ -15,7 +16,10 @@ TimeManager::TimeManager(Core::System& system_) : system{system_} { | |||
| 15 | Core::Timing::CreateEvent("Kernel::TimeManagerCallback", | 16 | Core::Timing::CreateEvent("Kernel::TimeManagerCallback", |
| 16 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { | 17 | [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) { |
| 17 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); | 18 | KThread* thread = reinterpret_cast<KThread*>(thread_handle); |
| 18 | thread->Wakeup(); | 19 | { |
| 20 | KScopedSchedulerLock sl(system.Kernel()); | ||
| 21 | thread->OnTimer(); | ||
| 22 | } | ||
| 19 | }); | 23 | }); |
| 20 | } | 24 | } |
| 21 | 25 | ||