diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/k_priority_queue.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.cpp | 3 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 37 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 13 |
4 files changed, 89 insertions, 0 deletions
diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index f4d71ad7e..0b894c8cf 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h | |||
| @@ -45,6 +45,7 @@ concept KPriorityQueueMember = !std::is_reference_v<T> && requires(T & t) { | |||
| 45 | 45 | ||
| 46 | { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; | 46 | { t.GetActiveCore() } -> Common::ConvertibleTo<s32>; |
| 47 | { t.GetPriority() } -> Common::ConvertibleTo<s32>; | 47 | { t.GetPriority() } -> Common::ConvertibleTo<s32>; |
| 48 | { t.IsDummyThread() } -> Common::ConvertibleTo<bool>; | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> | 51 | template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> |
| @@ -349,24 +350,49 @@ public: | |||
| 349 | 350 | ||
| 350 | // Mutators. | 351 | // Mutators. |
| 351 | constexpr void PushBack(Member* member) { | 352 | constexpr void PushBack(Member* member) { |
| 353 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 354 | if (member->IsDummyThread()) { | ||
| 355 | return; | ||
| 356 | } | ||
| 357 | |||
| 352 | this->PushBack(member->GetPriority(), member); | 358 | this->PushBack(member->GetPriority(), member); |
| 353 | } | 359 | } |
| 354 | 360 | ||
| 355 | constexpr void Remove(Member* member) { | 361 | constexpr void Remove(Member* member) { |
| 362 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 363 | if (member->IsDummyThread()) { | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | |||
| 356 | this->Remove(member->GetPriority(), member); | 367 | this->Remove(member->GetPriority(), member); |
| 357 | } | 368 | } |
| 358 | 369 | ||
| 359 | constexpr void MoveToScheduledFront(Member* member) { | 370 | constexpr void MoveToScheduledFront(Member* member) { |
| 371 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 372 | if (member->IsDummyThread()) { | ||
| 373 | return; | ||
| 374 | } | ||
| 375 | |||
| 360 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); | 376 | this->scheduled_queue.MoveToFront(member->GetPriority(), member->GetActiveCore(), member); |
| 361 | } | 377 | } |
| 362 | 378 | ||
| 363 | constexpr KThread* MoveToScheduledBack(Member* member) { | 379 | constexpr KThread* MoveToScheduledBack(Member* member) { |
| 380 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 381 | if (member->IsDummyThread()) { | ||
| 382 | return {}; | ||
| 383 | } | ||
| 384 | |||
| 364 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), | 385 | return this->scheduled_queue.MoveToBack(member->GetPriority(), member->GetActiveCore(), |
| 365 | member); | 386 | member); |
| 366 | } | 387 | } |
| 367 | 388 | ||
| 368 | // First class fancy operations. | 389 | // First class fancy operations. |
| 369 | constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { | 390 | constexpr void ChangePriority(s32 prev_priority, bool is_running, Member* member) { |
| 391 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 392 | if (member->IsDummyThread()) { | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | |||
| 370 | ASSERT(IsValidPriority(prev_priority)); | 396 | ASSERT(IsValidPriority(prev_priority)); |
| 371 | 397 | ||
| 372 | // Remove the member from the queues. | 398 | // Remove the member from the queues. |
| @@ -383,6 +409,11 @@ public: | |||
| 383 | 409 | ||
| 384 | constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, | 410 | constexpr void ChangeAffinityMask(s32 prev_core, const AffinityMaskType& prev_affinity, |
| 385 | Member* member) { | 411 | Member* member) { |
| 412 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 413 | if (member->IsDummyThread()) { | ||
| 414 | return; | ||
| 415 | } | ||
| 416 | |||
| 386 | // Get the new information. | 417 | // Get the new information. |
| 387 | const s32 priority = member->GetPriority(); | 418 | const s32 priority = member->GetPriority(); |
| 388 | const AffinityMaskType& new_affinity = member->GetAffinityMask(); | 419 | const AffinityMaskType& new_affinity = member->GetAffinityMask(); |
| @@ -412,6 +443,11 @@ public: | |||
| 412 | } | 443 | } |
| 413 | 444 | ||
| 414 | constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { | 445 | constexpr void ChangeCore(s32 prev_core, Member* member, bool to_front = false) { |
| 446 | // This is for host (dummy) threads that we do not want to enter the priority queue. | ||
| 447 | if (member->IsDummyThread()) { | ||
| 448 | return; | ||
| 449 | } | ||
| 450 | |||
| 415 | // Get the new information. | 451 | // Get the new information. |
| 416 | const s32 new_core = member->GetActiveCore(); | 452 | const s32 new_core = member->GetActiveCore(); |
| 417 | const s32 priority = member->GetPriority(); | 453 | const s32 priority = member->GetPriority(); |
diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 1b2a01869..b32d4f285 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp | |||
| @@ -406,6 +406,9 @@ void KScheduler::EnableScheduling(KernelCore& kernel, u64 cores_needing_scheduli | |||
| 406 | } else { | 406 | } else { |
| 407 | RescheduleCores(kernel, cores_needing_scheduling); | 407 | RescheduleCores(kernel, cores_needing_scheduling); |
| 408 | } | 408 | } |
| 409 | |||
| 410 | // Special case to ensure dummy threads that are waiting block. | ||
| 411 | current_thread->IfDummyThreadTryWait(); | ||
| 409 | } | 412 | } |
| 410 | 413 | ||
| 411 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { | 414 | u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 4cbf12c11..f42abb8a1 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -1075,12 +1075,46 @@ ResultCode KThread::Sleep(s64 timeout) { | |||
| 1075 | return ResultSuccess; | 1075 | return ResultSuccess; |
| 1076 | } | 1076 | } |
| 1077 | 1077 | ||
| 1078 | void KThread::IfDummyThreadTryWait() { | ||
| 1079 | if (!IsDummyThread()) { | ||
| 1080 | return; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | if (GetState() != ThreadState::Waiting) { | ||
| 1084 | return; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | // Block until we can grab the lock. | ||
| 1088 | KScopedSpinLock lk{dummy_wait_lock}; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | void KThread::IfDummyThreadBeginWait() { | ||
| 1092 | if (!IsDummyThread()) { | ||
| 1093 | return; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | // Ensure the thread will block when IfDummyThreadTryWait is called. | ||
| 1097 | dummy_wait_lock.Lock(); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | void KThread::IfDummyThreadEndWait() { | ||
| 1101 | if (!IsDummyThread()) { | ||
| 1102 | return; | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | // Ensure the thread will no longer block. | ||
| 1106 | dummy_wait_lock.Unlock(); | ||
| 1107 | } | ||
| 1108 | |||
| 1078 | void KThread::BeginWait(KThreadQueue* queue) { | 1109 | void KThread::BeginWait(KThreadQueue* queue) { |
| 1079 | // Set our state as waiting. | 1110 | // Set our state as waiting. |
| 1080 | SetState(ThreadState::Waiting); | 1111 | SetState(ThreadState::Waiting); |
| 1081 | 1112 | ||
| 1082 | // Set our wait queue. | 1113 | // Set our wait queue. |
| 1083 | wait_queue = queue; | 1114 | wait_queue = queue; |
| 1115 | |||
| 1116 | // Special case for dummy threads to ensure they block. | ||
| 1117 | IfDummyThreadBeginWait(); | ||
| 1084 | } | 1118 | } |
| 1085 | 1119 | ||
| 1086 | void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { | 1120 | void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { |
| @@ -1106,6 +1140,9 @@ void KThread::EndWait(ResultCode wait_result_) { | |||
| 1106 | } | 1140 | } |
| 1107 | 1141 | ||
| 1108 | wait_queue->EndWait(this, wait_result_); | 1142 | wait_queue->EndWait(this, wait_result_); |
| 1143 | |||
| 1144 | // Special case for dummy threads to wakeup if necessary. | ||
| 1145 | IfDummyThreadEndWait(); | ||
| 1109 | } | 1146 | } |
| 1110 | } | 1147 | } |
| 1111 | 1148 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 77b53a198..d058db62c 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -558,6 +558,10 @@ public: | |||
| 558 | return thread_type; | 558 | return thread_type; |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | [[nodiscard]] bool IsDummyThread() const { | ||
| 562 | return GetThreadType() == ThreadType::Dummy; | ||
| 563 | } | ||
| 564 | |||
| 561 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | 565 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { |
| 562 | wait_objects_for_debugging.clear(); | 566 | wait_objects_for_debugging.clear(); |
| 563 | wait_objects_for_debugging.reserve(objects.size()); | 567 | wait_objects_for_debugging.reserve(objects.size()); |
| @@ -632,6 +636,14 @@ public: | |||
| 632 | return condvar_key; | 636 | return condvar_key; |
| 633 | } | 637 | } |
| 634 | 638 | ||
| 639 | // Dummy threads (used for HLE host threads) cannot wait based on the guest scheduler, and | ||
| 640 | // therefore will not block on guest kernel synchronization primitives. These methods handle | ||
| 641 | // blocking as needed. | ||
| 642 | |||
| 643 | void IfDummyThreadTryWait(); | ||
| 644 | void IfDummyThreadBeginWait(); | ||
| 645 | void IfDummyThreadEndWait(); | ||
| 646 | |||
| 635 | private: | 647 | private: |
| 636 | static constexpr size_t PriorityInheritanceCountMax = 10; | 648 | static constexpr size_t PriorityInheritanceCountMax = 10; |
| 637 | union SyncObjectBuffer { | 649 | union SyncObjectBuffer { |
| @@ -750,6 +762,7 @@ private: | |||
| 750 | bool resource_limit_release_hint{}; | 762 | bool resource_limit_release_hint{}; |
| 751 | StackParameters stack_parameters{}; | 763 | StackParameters stack_parameters{}; |
| 752 | KSpinLock context_guard{}; | 764 | KSpinLock context_guard{}; |
| 765 | KSpinLock dummy_wait_lock{}; | ||
| 753 | 766 | ||
| 754 | // For emulation | 767 | // For emulation |
| 755 | std::shared_ptr<Common::Fiber> host_context{}; | 768 | std::shared_ptr<Common::Fiber> host_context{}; |