summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/kernel/k_priority_queue.h36
-rw-r--r--src/core/hle/kernel/k_scheduler.cpp3
-rw-r--r--src/core/hle/kernel/k_thread.cpp37
-rw-r--r--src/core/hle/kernel/k_thread.h13
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
50template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority> 51template <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
411u64 KScheduler::UpdateHighestPriorityThreads(KernelCore& kernel) { 414u64 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
1078void 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
1091void 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
1100void KThread::IfDummyThreadEndWait() {
1101 if (!IsDummyThread()) {
1102 return;
1103 }
1104
1105 // Ensure the thread will no longer block.
1106 dummy_wait_lock.Unlock();
1107}
1108
1078void KThread::BeginWait(KThreadQueue* queue) { 1109void 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
1086void KThread::NotifyAvailable(KSynchronizationObject* signaled_object, ResultCode wait_result_) { 1120void 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
635private: 647private:
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{};