diff options
| -rw-r--r-- | src/core/hle/kernel/k_address_arbiter.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_condition_variable.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_synchronization_object.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 1 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 21 | ||||
| -rw-r--r-- | src/yuzu/debugger/wait_tree.cpp | 43 |
8 files changed, 74 insertions, 4 deletions
diff --git a/src/core/hle/kernel/k_address_arbiter.cpp b/src/core/hle/kernel/k_address_arbiter.cpp index 7b712d31a..d9e702f13 100644 --- a/src/core/hle/kernel/k_address_arbiter.cpp +++ b/src/core/hle/kernel/k_address_arbiter.cpp | |||
| @@ -276,6 +276,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement | |||
| 276 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); | 276 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); |
| 277 | thread_tree.insert(*cur_thread); | 277 | thread_tree.insert(*cur_thread); |
| 278 | cur_thread->SetState(ThreadState::Waiting); | 278 | cur_thread->SetState(ThreadState::Waiting); |
| 279 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | ||
| 279 | } | 280 | } |
| 280 | 281 | ||
| 281 | // Cancel the timer wait. | 282 | // Cancel the timer wait. |
| @@ -339,6 +340,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { | |||
| 339 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); | 340 | cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); |
| 340 | thread_tree.insert(*cur_thread); | 341 | thread_tree.insert(*cur_thread); |
| 341 | cur_thread->SetState(ThreadState::Waiting); | 342 | cur_thread->SetState(ThreadState::Waiting); |
| 343 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); | ||
| 342 | } | 344 | } |
| 343 | 345 | ||
| 344 | // Cancel the timer wait. | 346 | // Cancel the timer wait. |
diff --git a/src/core/hle/kernel/k_condition_variable.cpp b/src/core/hle/kernel/k_condition_variable.cpp index ef5c17409..49a068310 100644 --- a/src/core/hle/kernel/k_condition_variable.cpp +++ b/src/core/hle/kernel/k_condition_variable.cpp | |||
| @@ -133,6 +133,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val | |||
| 133 | cur_thread->SetAddressKey(addr, value); | 133 | cur_thread->SetAddressKey(addr, value); |
| 134 | owner_thread->AddWaiter(cur_thread); | 134 | owner_thread->AddWaiter(cur_thread); |
| 135 | cur_thread->SetState(ThreadState::Waiting); | 135 | cur_thread->SetState(ThreadState::Waiting); |
| 136 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||
| 136 | cur_thread->SetMutexWaitAddressForDebugging(addr); | 137 | cur_thread->SetMutexWaitAddressForDebugging(addr); |
| 137 | } | 138 | } |
| 138 | } | 139 | } |
| @@ -315,6 +316,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout) | |||
| 315 | // If the timeout is non-zero, set the thread as waiting. | 316 | // If the timeout is non-zero, set the thread as waiting. |
| 316 | if (timeout != 0) { | 317 | if (timeout != 0) { |
| 317 | cur_thread->SetState(ThreadState::Waiting); | 318 | cur_thread->SetState(ThreadState::Waiting); |
| 319 | cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar); | ||
| 318 | cur_thread->SetMutexWaitAddressForDebugging(addr); | 320 | cur_thread->SetMutexWaitAddressForDebugging(addr); |
| 319 | } | 321 | } |
| 320 | } | 322 | } |
diff --git a/src/core/hle/kernel/k_synchronization_object.cpp b/src/core/hle/kernel/k_synchronization_object.cpp index 11b989ecd..1c508cb55 100644 --- a/src/core/hle/kernel/k_synchronization_object.cpp +++ b/src/core/hle/kernel/k_synchronization_object.cpp | |||
| @@ -78,6 +78,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index, | |||
| 78 | thread->SetCancellable(); | 78 | thread->SetCancellable(); |
| 79 | thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); | 79 | thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); |
| 80 | thread->SetState(ThreadState::Waiting); | 80 | thread->SetState(ThreadState::Waiting); |
| 81 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization); | ||
| 81 | } | 82 | } |
| 82 | 83 | ||
| 83 | // The lock/sleep is done, so we should be able to get our result. | 84 | // The lock/sleep is done, so we should be able to get our result. |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 8d03f16fb..c0ff287a6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -605,6 +605,8 @@ void KernelCore::Suspend(bool in_suspention) { | |||
| 605 | const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; | 605 | const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; |
| 606 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { | 606 | for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { |
| 607 | impl->suspend_threads[i]->SetState(state); | 607 | impl->suspend_threads[i]->SetState(state); |
| 608 | impl->suspend_threads[i]->SetWaitReasonForDebugging( | ||
| 609 | ThreadWaitReasonForDebugging::Suspended); | ||
| 608 | } | 610 | } |
| 609 | } | 611 | } |
| 610 | } | 612 | } |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 99bb4ea20..cc8b661af 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -347,6 +347,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) { | |||
| 347 | { | 347 | { |
| 348 | KScopedSchedulerLock lock(kernel); | 348 | KScopedSchedulerLock lock(kernel); |
| 349 | thread->SetState(ThreadState::Waiting); | 349 | thread->SetState(ThreadState::Waiting); |
| 350 | thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC); | ||
| 350 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); | 351 | session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); |
| 351 | } | 352 | } |
| 352 | 353 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index eda56c31c..d97323255 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -215,7 +215,10 @@ VAddr Thread::GetCommandBufferAddress() const { | |||
| 215 | void Thread::SetState(ThreadState state) { | 215 | void Thread::SetState(ThreadState state) { |
| 216 | KScopedSchedulerLock sl(kernel); | 216 | KScopedSchedulerLock sl(kernel); |
| 217 | 217 | ||
| 218 | SetMutexWaitAddressForDebugging(0); | 218 | // Clear debugging state |
| 219 | SetMutexWaitAddressForDebugging({}); | ||
| 220 | SetWaitReasonForDebugging({}); | ||
| 221 | |||
| 219 | const ThreadState old_state = thread_state; | 222 | const ThreadState old_state = thread_state; |
| 220 | thread_state = | 223 | thread_state = |
| 221 | static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); | 224 | static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); |
| @@ -386,6 +389,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) { | |||
| 386 | { | 389 | { |
| 387 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); | 390 | KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); |
| 388 | SetState(ThreadState::Waiting); | 391 | SetState(ThreadState::Waiting); |
| 392 | SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep); | ||
| 389 | } | 393 | } |
| 390 | 394 | ||
| 391 | if (event_handle != InvalidHandle) { | 395 | if (event_handle != InvalidHandle) { |
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 820ea524f..6b66c9a0e 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -114,6 +114,16 @@ enum class ThreadSchedFlags : u32 { | |||
| 114 | KernelInitPauseFlag = 1 << 8, | 114 | KernelInitPauseFlag = 1 << 8, |
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | enum class ThreadWaitReasonForDebugging : u32 { | ||
| 118 | None, ///< Thread is not waiting | ||
| 119 | Sleep, ///< Thread is waiting due to a SleepThread SVC | ||
| 120 | IPC, ///< Thread is waiting for the reply from an IPC request | ||
| 121 | Synchronization, ///< Thread is waiting due to a WaitSynchronization SVC | ||
| 122 | ConditionVar, ///< Thread is waiting due to a WaitProcessWideKey SVC | ||
| 123 | Arbitration, ///< Thread is waiting due to a SignalToAddress/WaitForAddress SVC | ||
| 124 | Suspended, ///< Thread is waiting due to process suspension | ||
| 125 | }; | ||
| 126 | |||
| 117 | class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { | 127 | class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { |
| 118 | friend class KScheduler; | 128 | friend class KScheduler; |
| 119 | friend class Process; | 129 | friend class Process; |
| @@ -515,6 +525,14 @@ public: | |||
| 515 | disable_count--; | 525 | disable_count--; |
| 516 | } | 526 | } |
| 517 | 527 | ||
| 528 | void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) { | ||
| 529 | wait_reason_for_debugging = reason; | ||
| 530 | } | ||
| 531 | |||
| 532 | [[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const { | ||
| 533 | return wait_reason_for_debugging; | ||
| 534 | } | ||
| 535 | |||
| 518 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { | 536 | void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { |
| 519 | wait_objects_for_debugging.clear(); | 537 | wait_objects_for_debugging.clear(); |
| 520 | wait_objects_for_debugging.reserve(objects.size()); | 538 | wait_objects_for_debugging.reserve(objects.size()); |
| @@ -708,6 +726,9 @@ private: | |||
| 708 | /// The current mutex wait address. This is used for debugging only. | 726 | /// The current mutex wait address. This is used for debugging only. |
| 709 | VAddr mutex_wait_address_for_debugging{}; | 727 | VAddr mutex_wait_address_for_debugging{}; |
| 710 | 728 | ||
| 729 | /// The reason the thread is waiting. This is used for debugging only. | ||
| 730 | ThreadWaitReasonForDebugging wait_reason_for_debugging{}; | ||
| 731 | |||
| 711 | KSynchronizationObject* signaling_object; | 732 | KSynchronizationObject* signaling_object; |
| 712 | ResultCode signaling_result{RESULT_SUCCESS}; | 733 | ResultCode signaling_result{RESULT_SUCCESS}; |
| 713 | 734 | ||
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index deefb0ba0..a93b5d3c2 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp | |||
| @@ -251,7 +251,29 @@ QString WaitTreeThread::GetText() const { | |||
| 251 | } | 251 | } |
| 252 | break; | 252 | break; |
| 253 | case Kernel::ThreadState::Waiting: | 253 | case Kernel::ThreadState::Waiting: |
| 254 | status = tr("waiting"); | 254 | switch (thread.GetWaitReasonForDebugging()) { |
| 255 | case Kernel::ThreadWaitReasonForDebugging::Sleep: | ||
| 256 | status = tr("sleeping"); | ||
| 257 | break; | ||
| 258 | case Kernel::ThreadWaitReasonForDebugging::IPC: | ||
| 259 | status = tr("waiting for IPC reply"); | ||
| 260 | break; | ||
| 261 | case Kernel::ThreadWaitReasonForDebugging::Synchronization: | ||
| 262 | status = tr("waiting for objects"); | ||
| 263 | break; | ||
| 264 | case Kernel::ThreadWaitReasonForDebugging::ConditionVar: | ||
| 265 | status = tr("waiting for condition variable"); | ||
| 266 | break; | ||
| 267 | case Kernel::ThreadWaitReasonForDebugging::Arbitration: | ||
| 268 | status = tr("waiting for address arbiter"); | ||
| 269 | break; | ||
| 270 | case Kernel::ThreadWaitReasonForDebugging::Suspended: | ||
| 271 | status = tr("waiting for suspend resume"); | ||
| 272 | break; | ||
| 273 | default: | ||
| 274 | status = tr("waiting"); | ||
| 275 | break; | ||
| 276 | } | ||
| 255 | break; | 277 | break; |
| 256 | case Kernel::ThreadState::Initialized: | 278 | case Kernel::ThreadState::Initialized: |
| 257 | status = tr("initialized"); | 279 | status = tr("initialized"); |
| @@ -288,7 +310,20 @@ QColor WaitTreeThread::GetColor() const { | |||
| 288 | return QColor(WaitTreeColors[2][color_index]); | 310 | return QColor(WaitTreeColors[2][color_index]); |
| 289 | } | 311 | } |
| 290 | case Kernel::ThreadState::Waiting: | 312 | case Kernel::ThreadState::Waiting: |
| 291 | return QColor(WaitTreeColors[3][color_index]); | 313 | switch (thread.GetWaitReasonForDebugging()) { |
| 314 | case Kernel::ThreadWaitReasonForDebugging::IPC: | ||
| 315 | return QColor(WaitTreeColors[4][color_index]); | ||
| 316 | case Kernel::ThreadWaitReasonForDebugging::Sleep: | ||
| 317 | return QColor(WaitTreeColors[5][color_index]); | ||
| 318 | case Kernel::ThreadWaitReasonForDebugging::Synchronization: | ||
| 319 | case Kernel::ThreadWaitReasonForDebugging::ConditionVar: | ||
| 320 | case Kernel::ThreadWaitReasonForDebugging::Arbitration: | ||
| 321 | case Kernel::ThreadWaitReasonForDebugging::Suspended: | ||
| 322 | return QColor(WaitTreeColors[6][color_index]); | ||
| 323 | break; | ||
| 324 | default: | ||
| 325 | return QColor(WaitTreeColors[3][color_index]); | ||
| 326 | } | ||
| 292 | case Kernel::ThreadState::Initialized: | 327 | case Kernel::ThreadState::Initialized: |
| 293 | return QColor(WaitTreeColors[7][color_index]); | 328 | return QColor(WaitTreeColors[7][color_index]); |
| 294 | case Kernel::ThreadState::Terminated: | 329 | case Kernel::ThreadState::Terminated: |
| @@ -339,7 +374,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 339 | list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); | 374 | list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); |
| 340 | } | 375 | } |
| 341 | 376 | ||
| 342 | if (thread.GetState() == Kernel::ThreadState::Waiting) { | 377 | if (thread.GetState() == Kernel::ThreadState::Waiting && |
| 378 | thread.GetWaitReasonForDebugging() == | ||
| 379 | Kernel::ThreadWaitReasonForDebugging::Synchronization) { | ||
| 343 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(), | 380 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(), |
| 344 | thread.IsCancellable())); | 381 | thread.IsCancellable())); |
| 345 | } | 382 | } |