diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/hle_ipc.h | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_priority_queue.h | 36 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_scheduler.cpp | 9 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_server_session.cpp | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.cpp | 49 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_thread.h | 20 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/service_thread.cpp | 5 | ||||
| -rw-r--r-- | src/yuzu/debugger/wait_tree.cpp | 4 |
9 files changed, 120 insertions, 40 deletions
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 55e6fb9f7..754b41ff6 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -341,10 +341,6 @@ public: | |||
| 341 | return *thread; | 341 | return *thread; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | bool IsThreadWaiting() const { | ||
| 345 | return is_thread_waiting; | ||
| 346 | } | ||
| 347 | |||
| 348 | private: | 344 | private: |
| 349 | friend class IPC::ResponseBuilder; | 345 | friend class IPC::ResponseBuilder; |
| 350 | 346 | ||
| @@ -379,7 +375,6 @@ private: | |||
| 379 | u32 domain_offset{}; | 375 | u32 domain_offset{}; |
| 380 | 376 | ||
| 381 | std::shared_ptr<SessionRequestManager> manager; | 377 | std::shared_ptr<SessionRequestManager> manager; |
| 382 | bool is_thread_waiting{}; | ||
| 383 | 378 | ||
| 384 | KernelCore& kernel; | 379 | KernelCore& kernel; |
| 385 | Core::Memory::Memory& memory; | 380 | Core::Memory::Memory& memory; |
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 f900b2e7a..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) { |
| @@ -739,6 +742,12 @@ void KScheduler::ScheduleImpl() { | |||
| 739 | next_thread = idle_thread; | 742 | next_thread = idle_thread; |
| 740 | } | 743 | } |
| 741 | 744 | ||
| 745 | // We never want to schedule a dummy thread, as these are only used by host threads for locking. | ||
| 746 | if (next_thread->GetThreadType() == ThreadType::Dummy) { | ||
| 747 | ASSERT_MSG(false, "Dummy threads should never be scheduled!"); | ||
| 748 | next_thread = idle_thread; | ||
| 749 | } | ||
| 750 | |||
| 742 | // If we're not actually switching thread, there's nothing to do. | 751 | // If we're not actually switching thread, there's nothing to do. |
| 743 | if (next_thread == current_thread.load()) { | 752 | if (next_thread == current_thread.load()) { |
| 744 | previous_thread->EnableDispatch(); | 753 | previous_thread->EnableDispatch(); |
diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index d4e4a6b06..4d94eb9cf 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/logging/log.h" | 10 | #include "common/logging/log.h" |
| 11 | #include "common/scope_exit.h" | ||
| 12 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 13 | #include "core/hle/ipc_helpers.h" | 12 | #include "core/hle/ipc_helpers.h" |
| 14 | #include "core/hle/kernel/hle_ipc.h" | 13 | #include "core/hle/kernel/hle_ipc.h" |
| @@ -123,20 +122,10 @@ ResultCode KServerSession::QueueSyncRequest(KThread* thread, Core::Memory::Memor | |||
| 123 | 122 | ||
| 124 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); | 123 | context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf); |
| 125 | 124 | ||
| 126 | // In the event that something fails here, stub a result to prevent the game from crashing. | ||
| 127 | // This is a work-around in the event that somehow we process a service request after the | ||
| 128 | // session has been closed by the game. This has been observed to happen rarely in Pokemon | ||
| 129 | // Sword/Shield and is likely a result of us using host threads/scheduling for services. | ||
| 130 | // TODO(bunnei): Find a better solution here. | ||
| 131 | auto error_guard = SCOPE_GUARD({ CompleteSyncRequest(*context); }); | ||
| 132 | |||
| 133 | // Ensure we have a session request handler | 125 | // Ensure we have a session request handler |
| 134 | if (manager->HasSessionRequestHandler(*context)) { | 126 | if (manager->HasSessionRequestHandler(*context)) { |
| 135 | if (auto strong_ptr = manager->GetServiceThread().lock()) { | 127 | if (auto strong_ptr = manager->GetServiceThread().lock()) { |
| 136 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); | 128 | strong_ptr->QueueSyncRequest(*parent, std::move(context)); |
| 137 | |||
| 138 | // We succeeded. | ||
| 139 | error_guard.Cancel(); | ||
| 140 | } else { | 129 | } else { |
| 141 | ASSERT_MSG(false, "strong_ptr is nullptr!"); | 130 | ASSERT_MSG(false, "strong_ptr is nullptr!"); |
| 142 | } | 131 | } |
| @@ -171,13 +160,8 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { | |||
| 171 | convert_to_domain = false; | 160 | convert_to_domain = false; |
| 172 | } | 161 | } |
| 173 | 162 | ||
| 174 | // Some service requests require the thread to block | 163 | // The calling thread is waiting for this request to complete, so wake it up. |
| 175 | { | 164 | context.GetThread().EndWait(result); |
| 176 | KScopedSchedulerLock lock(kernel); | ||
| 177 | if (!context.IsThreadWaiting()) { | ||
| 178 | context.GetThread().EndWait(result); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | 165 | ||
| 182 | return result; | 166 | return result; |
| 183 | } | 167 | } |
diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index 7a5e6fc08..f42abb8a1 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp | |||
| @@ -106,7 +106,7 @@ KThread::~KThread() = default; | |||
| 106 | ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, | 106 | ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_stack_top, s32 prio, |
| 107 | s32 virt_core, KProcess* owner, ThreadType type) { | 107 | s32 virt_core, KProcess* owner, ThreadType type) { |
| 108 | // Assert parameters are valid. | 108 | // Assert parameters are valid. |
| 109 | ASSERT((type == ThreadType::Main) || | 109 | ASSERT((type == ThreadType::Main) || (type == ThreadType::Dummy) || |
| 110 | (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); | 110 | (Svc::HighestThreadPriority <= prio && prio <= Svc::LowestThreadPriority)); |
| 111 | ASSERT((owner != nullptr) || (type != ThreadType::User)); | 111 | ASSERT((owner != nullptr) || (type != ThreadType::User)); |
| 112 | ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>())); | 112 | ASSERT(0 <= virt_core && virt_core < static_cast<s32>(Common::BitSize<u64>())); |
| @@ -140,7 +140,7 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s | |||
| 140 | UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); | 140 | UNREACHABLE_MSG("KThread::Initialize: Unknown ThreadType {}", static_cast<u32>(type)); |
| 141 | break; | 141 | break; |
| 142 | } | 142 | } |
| 143 | thread_type_for_debugging = type; | 143 | thread_type = type; |
| 144 | 144 | ||
| 145 | // Set the ideal core ID and affinity mask. | 145 | // Set the ideal core ID and affinity mask. |
| 146 | virtual_ideal_core_id = virt_core; | 146 | virtual_ideal_core_id = virt_core; |
| @@ -262,7 +262,7 @@ ResultCode KThread::InitializeThread(KThread* thread, KThreadFunction func, uint | |||
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | ResultCode KThread::InitializeDummyThread(KThread* thread) { | 264 | ResultCode KThread::InitializeDummyThread(KThread* thread) { |
| 265 | return thread->Initialize({}, {}, {}, DefaultThreadPriority, 3, {}, ThreadType::Dummy); | 265 | return thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy); |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { | 268 | ResultCode KThread::InitializeIdleThread(Core::System& system, KThread* thread, s32 virt_core) { |
| @@ -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_) { |
| @@ -1099,7 +1133,16 @@ void KThread::EndWait(ResultCode wait_result_) { | |||
| 1099 | 1133 | ||
| 1100 | // If we're waiting, notify our queue that we're available. | 1134 | // If we're waiting, notify our queue that we're available. |
| 1101 | if (GetState() == ThreadState::Waiting) { | 1135 | if (GetState() == ThreadState::Waiting) { |
| 1136 | if (wait_queue == nullptr) { | ||
| 1137 | // This should never happen, but avoid a hard crash below to get this logged. | ||
| 1138 | ASSERT_MSG(false, "wait_queue is nullptr!"); | ||
| 1139 | return; | ||
| 1140 | } | ||
| 1141 | |||
| 1102 | 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(); | ||
| 1103 | } | 1146 | } |
| 1104 | } | 1147 | } |
| 1105 | 1148 | ||
diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index cc427f6cf..d058db62c 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h | |||
| @@ -112,6 +112,7 @@ private: | |||
| 112 | public: | 112 | public: |
| 113 | static constexpr s32 DefaultThreadPriority = 44; | 113 | static constexpr s32 DefaultThreadPriority = 44; |
| 114 | static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; | 114 | static constexpr s32 IdleThreadPriority = Svc::LowestThreadPriority + 1; |
| 115 | static constexpr s32 DummyThreadPriority = Svc::LowestThreadPriority + 2; | ||
| 115 | 116 | ||
| 116 | explicit KThread(KernelCore& kernel_); | 117 | explicit KThread(KernelCore& kernel_); |
| 117 | ~KThread() override; | 118 | ~KThread() override; |
| @@ -553,8 +554,12 @@ public: | |||
| 553 | return wait_reason_for_debugging; | 554 | return wait_reason_for_debugging; |
| 554 | } | 555 | } |
| 555 | 556 | ||
| 556 | [[nodiscard]] ThreadType GetThreadTypeForDebugging() const { | 557 | [[nodiscard]] ThreadType GetThreadType() const { |
| 557 | return thread_type_for_debugging; | 558 | return thread_type; |
| 559 | } | ||
| 560 | |||
| 561 | [[nodiscard]] bool IsDummyThread() const { | ||
| 562 | return GetThreadType() == ThreadType::Dummy; | ||
| 558 | } | 563 | } |
| 559 | 564 | ||
| 560 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | 565 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { |
| @@ -631,6 +636,14 @@ public: | |||
| 631 | return condvar_key; | 636 | return condvar_key; |
| 632 | } | 637 | } |
| 633 | 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 | |||
| 634 | private: | 647 | private: |
| 635 | static constexpr size_t PriorityInheritanceCountMax = 10; | 648 | static constexpr size_t PriorityInheritanceCountMax = 10; |
| 636 | union SyncObjectBuffer { | 649 | union SyncObjectBuffer { |
| @@ -749,16 +762,17 @@ private: | |||
| 749 | bool resource_limit_release_hint{}; | 762 | bool resource_limit_release_hint{}; |
| 750 | StackParameters stack_parameters{}; | 763 | StackParameters stack_parameters{}; |
| 751 | KSpinLock context_guard{}; | 764 | KSpinLock context_guard{}; |
| 765 | KSpinLock dummy_wait_lock{}; | ||
| 752 | 766 | ||
| 753 | // For emulation | 767 | // For emulation |
| 754 | std::shared_ptr<Common::Fiber> host_context{}; | 768 | std::shared_ptr<Common::Fiber> host_context{}; |
| 755 | bool is_single_core{}; | 769 | bool is_single_core{}; |
| 770 | ThreadType thread_type{}; | ||
| 756 | 771 | ||
| 757 | // For debugging | 772 | // For debugging |
| 758 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; | 773 | std::vector<KSynchronizationObject*> wait_objects_for_debugging; |
| 759 | VAddr mutex_wait_address_for_debugging{}; | 774 | VAddr mutex_wait_address_for_debugging{}; |
| 760 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | 775 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; |
| 761 | ThreadType thread_type_for_debugging{}; | ||
| 762 | 776 | ||
| 763 | public: | 777 | public: |
| 764 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; | 778 | using ConditionVariableThreadTreeType = ConditionVariableThreadTree; |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 887c1fd27..49c0714ed 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -301,12 +301,10 @@ struct KernelCore::Impl { | |||
| 301 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time | 301 | // Gets the dummy KThread for the caller, allocating a new one if this is the first time |
| 302 | KThread* GetHostDummyThread() { | 302 | KThread* GetHostDummyThread() { |
| 303 | auto make_thread = [this]() { | 303 | auto make_thread = [this]() { |
| 304 | std::lock_guard lk(dummy_thread_lock); | 304 | KThread* thread = KThread::Create(system.Kernel()); |
| 305 | auto& thread = dummy_threads.emplace_back(std::make_unique<KThread>(system.Kernel())); | 305 | ASSERT(KThread::InitializeDummyThread(thread).IsSuccess()); |
| 306 | KAutoObject::Create(thread.get()); | ||
| 307 | ASSERT(KThread::InitializeDummyThread(thread.get()).IsSuccess()); | ||
| 308 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); | 306 | thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId())); |
| 309 | return thread.get(); | 307 | return thread; |
| 310 | }; | 308 | }; |
| 311 | 309 | ||
| 312 | thread_local KThread* saved_thread = make_thread(); | 310 | thread_local KThread* saved_thread = make_thread(); |
| @@ -731,7 +729,6 @@ struct KernelCore::Impl { | |||
| 731 | std::mutex server_sessions_lock; | 729 | std::mutex server_sessions_lock; |
| 732 | std::mutex registered_objects_lock; | 730 | std::mutex registered_objects_lock; |
| 733 | std::mutex registered_in_use_objects_lock; | 731 | std::mutex registered_in_use_objects_lock; |
| 734 | std::mutex dummy_thread_lock; | ||
| 735 | 732 | ||
| 736 | std::atomic<u32> next_object_id{0}; | 733 | std::atomic<u32> next_object_id{0}; |
| 737 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; | 734 | std::atomic<u64> next_kernel_process_id{KProcess::InitialKIPIDMin}; |
| @@ -788,9 +785,6 @@ struct KernelCore::Impl { | |||
| 788 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; | 785 | std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; |
| 789 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; | 786 | std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; |
| 790 | 787 | ||
| 791 | // Specifically tracked to be automatically destroyed with kernel | ||
| 792 | std::vector<std::unique_ptr<KThread>> dummy_threads; | ||
| 793 | |||
| 794 | bool is_multicore{}; | 788 | bool is_multicore{}; |
| 795 | std::atomic_bool is_shutting_down{}; | 789 | std::atomic_bool is_shutting_down{}; |
| 796 | bool is_phantom_mode_for_singlecore{}; | 790 | bool is_phantom_mode_for_singlecore{}; |
diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 03f3dec10..4eb3a5988 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/scope_exit.h" | 12 | #include "common/scope_exit.h" |
| 13 | #include "common/thread.h" | 13 | #include "common/thread.h" |
| 14 | #include "core/hle/kernel/k_session.h" | 14 | #include "core/hle/kernel/k_session.h" |
| 15 | #include "core/hle/kernel/k_thread.h" | ||
| 15 | #include "core/hle/kernel/kernel.h" | 16 | #include "core/hle/kernel/kernel.h" |
| 16 | #include "core/hle/kernel/service_thread.h" | 17 | #include "core/hle/kernel/service_thread.h" |
| 17 | 18 | ||
| @@ -50,6 +51,10 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std | |||
| 50 | 51 | ||
| 51 | kernel.RegisterHostThread(); | 52 | kernel.RegisterHostThread(); |
| 52 | 53 | ||
| 54 | // Ensure the dummy thread allocated for this host thread is closed on exit. | ||
| 55 | auto* dummy_thread = kernel.GetCurrentEmuThread(); | ||
| 56 | SCOPE_EXIT({ dummy_thread->Close(); }); | ||
| 57 | |||
| 53 | while (true) { | 58 | while (true) { |
| 54 | std::function<void()> task; | 59 | std::function<void()> task; |
| 55 | 60 | ||
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 1f41c46c4..2d1a2d9cb 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -95,7 +95,7 @@ std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList( | |||
| 95 | std::size_t row = 0; | 95 | std::size_t row = 0; |
| 96 | auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { | 96 | auto add_threads = [&](const std::vector<Kernel::KThread*>& threads) { |
| 97 | for (std::size_t i = 0; i < threads.size(); ++i) { | 97 | for (std::size_t i = 0; i < threads.size(); ++i) { |
| 98 | if (threads[i]->GetThreadTypeForDebugging() == Kernel::ThreadType::User) { | 98 | if (threads[i]->GetThreadType() == Kernel::ThreadType::User) { |
| 99 | item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system)); | 99 | item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i], system)); |
| 100 | item_list.back()->row = row; | 100 | item_list.back()->row = row; |
| 101 | } | 101 | } |
| @@ -153,7 +153,7 @@ QString WaitTreeCallstack::GetText() const { | |||
| 153 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { | 153 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { |
| 154 | std::vector<std::unique_ptr<WaitTreeItem>> list; | 154 | std::vector<std::unique_ptr<WaitTreeItem>> list; |
| 155 | 155 | ||
| 156 | if (thread.GetThreadTypeForDebugging() != Kernel::ThreadType::User) { | 156 | if (thread.GetThreadType() != Kernel::ThreadType::User) { |
| 157 | return list; | 157 | return list; |
| 158 | } | 158 | } |
| 159 | 159 | ||