hle: kernel: thread: Preserve thread wait reason for debugging only.

- This is decoupled from core functionality and used for debugging only.
This commit is contained in:
bunnei 2021-01-10 14:29:02 -08:00
parent 81c1bfafea
commit 03dfc8d8e7
8 changed files with 74 additions and 4 deletions

View file

@ -276,6 +276,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement
cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr);
thread_tree.insert(*cur_thread); thread_tree.insert(*cur_thread);
cur_thread->SetState(ThreadState::Waiting); cur_thread->SetState(ThreadState::Waiting);
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
} }
// Cancel the timer wait. // Cancel the timer wait.
@ -339,6 +340,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) {
cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr);
thread_tree.insert(*cur_thread); thread_tree.insert(*cur_thread);
cur_thread->SetState(ThreadState::Waiting); cur_thread->SetState(ThreadState::Waiting);
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration);
} }
// Cancel the timer wait. // Cancel the timer wait.

View file

@ -133,6 +133,7 @@ ResultCode KConditionVariable::WaitForAddress(Handle handle, VAddr addr, u32 val
cur_thread->SetAddressKey(addr, value); cur_thread->SetAddressKey(addr, value);
owner_thread->AddWaiter(cur_thread); owner_thread->AddWaiter(cur_thread);
cur_thread->SetState(ThreadState::Waiting); cur_thread->SetState(ThreadState::Waiting);
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
cur_thread->SetMutexWaitAddressForDebugging(addr); cur_thread->SetMutexWaitAddressForDebugging(addr);
} }
} }
@ -315,6 +316,7 @@ ResultCode KConditionVariable::Wait(VAddr addr, u64 key, u32 value, s64 timeout)
// If the timeout is non-zero, set the thread as waiting. // If the timeout is non-zero, set the thread as waiting.
if (timeout != 0) { if (timeout != 0) {
cur_thread->SetState(ThreadState::Waiting); cur_thread->SetState(ThreadState::Waiting);
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::ConditionVar);
cur_thread->SetMutexWaitAddressForDebugging(addr); cur_thread->SetMutexWaitAddressForDebugging(addr);
} }
} }

View file

@ -78,6 +78,7 @@ ResultCode KSynchronizationObject::Wait(KernelCore& kernel, s32* out_index,
thread->SetCancellable(); thread->SetCancellable();
thread->SetSyncedObject(nullptr, Svc::ResultTimedOut); thread->SetSyncedObject(nullptr, Svc::ResultTimedOut);
thread->SetState(ThreadState::Waiting); thread->SetState(ThreadState::Waiting);
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Synchronization);
} }
// The lock/sleep is done, so we should be able to get our result. // The lock/sleep is done, so we should be able to get our result.

View file

@ -605,6 +605,8 @@ void KernelCore::Suspend(bool in_suspention) {
const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting; const auto state = should_suspend ? ThreadState::Runnable : ThreadState::Waiting;
for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
impl->suspend_threads[i]->SetState(state); impl->suspend_threads[i]->SetState(state);
impl->suspend_threads[i]->SetWaitReasonForDebugging(
ThreadWaitReasonForDebugging::Suspended);
} }
} }
} }

View file

@ -347,6 +347,7 @@ static ResultCode SendSyncRequest(Core::System& system, Handle handle) {
{ {
KScopedSchedulerLock lock(kernel); KScopedSchedulerLock lock(kernel);
thread->SetState(ThreadState::Waiting); thread->SetState(ThreadState::Waiting);
thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::IPC);
session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming()); session->SendSyncRequest(SharedFrom(thread), system.Memory(), system.CoreTiming());
} }

View file

@ -215,7 +215,10 @@ VAddr Thread::GetCommandBufferAddress() const {
void Thread::SetState(ThreadState state) { void Thread::SetState(ThreadState state) {
KScopedSchedulerLock sl(kernel); KScopedSchedulerLock sl(kernel);
SetMutexWaitAddressForDebugging(0); // Clear debugging state
SetMutexWaitAddressForDebugging({});
SetWaitReasonForDebugging({});
const ThreadState old_state = thread_state; const ThreadState old_state = thread_state;
thread_state = thread_state =
static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask)); static_cast<ThreadState>((old_state & ~ThreadState::Mask) | (state & ThreadState::Mask));
@ -386,6 +389,7 @@ ResultCode Thread::Sleep(s64 nanoseconds) {
{ {
KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds); KScopedSchedulerLockAndSleep lock(kernel, event_handle, this, nanoseconds);
SetState(ThreadState::Waiting); SetState(ThreadState::Waiting);
SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Sleep);
} }
if (event_handle != InvalidHandle) { if (event_handle != InvalidHandle) {

View file

@ -114,6 +114,16 @@ enum class ThreadSchedFlags : u32 {
KernelInitPauseFlag = 1 << 8, KernelInitPauseFlag = 1 << 8,
}; };
enum class ThreadWaitReasonForDebugging : u32 {
None, ///< Thread is not waiting
Sleep, ///< Thread is waiting due to a SleepThread SVC
IPC, ///< Thread is waiting for the reply from an IPC request
Synchronization, ///< Thread is waiting due to a WaitSynchronization SVC
ConditionVar, ///< Thread is waiting due to a WaitProcessWideKey SVC
Arbitration, ///< Thread is waiting due to a SignalToAddress/WaitForAddress SVC
Suspended, ///< Thread is waiting due to process suspension
};
class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> { class Thread final : public KSynchronizationObject, public boost::intrusive::list_base_hook<> {
friend class KScheduler; friend class KScheduler;
friend class Process; friend class Process;
@ -515,6 +525,14 @@ public:
disable_count--; disable_count--;
} }
void SetWaitReasonForDebugging(ThreadWaitReasonForDebugging reason) {
wait_reason_for_debugging = reason;
}
[[nodiscard]] ThreadWaitReasonForDebugging GetWaitReasonForDebugging() const {
return wait_reason_for_debugging;
}
void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) { void SetWaitObjectsForDebugging(const std::span<KSynchronizationObject*>& objects) {
wait_objects_for_debugging.clear(); wait_objects_for_debugging.clear();
wait_objects_for_debugging.reserve(objects.size()); wait_objects_for_debugging.reserve(objects.size());
@ -708,6 +726,9 @@ private:
/// The current mutex wait address. This is used for debugging only. /// The current mutex wait address. This is used for debugging only.
VAddr mutex_wait_address_for_debugging{}; VAddr mutex_wait_address_for_debugging{};
/// The reason the thread is waiting. This is used for debugging only.
ThreadWaitReasonForDebugging wait_reason_for_debugging{};
KSynchronizationObject* signaling_object; KSynchronizationObject* signaling_object;
ResultCode signaling_result{RESULT_SUCCESS}; ResultCode signaling_result{RESULT_SUCCESS};

View file

@ -251,8 +251,30 @@ QString WaitTreeThread::GetText() const {
} }
break; break;
case Kernel::ThreadState::Waiting: case Kernel::ThreadState::Waiting:
switch (thread.GetWaitReasonForDebugging()) {
case Kernel::ThreadWaitReasonForDebugging::Sleep:
status = tr("sleeping");
break;
case Kernel::ThreadWaitReasonForDebugging::IPC:
status = tr("waiting for IPC reply");
break;
case Kernel::ThreadWaitReasonForDebugging::Synchronization:
status = tr("waiting for objects");
break;
case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
status = tr("waiting for condition variable");
break;
case Kernel::ThreadWaitReasonForDebugging::Arbitration:
status = tr("waiting for address arbiter");
break;
case Kernel::ThreadWaitReasonForDebugging::Suspended:
status = tr("waiting for suspend resume");
break;
default:
status = tr("waiting"); status = tr("waiting");
break; break;
}
break;
case Kernel::ThreadState::Initialized: case Kernel::ThreadState::Initialized:
status = tr("initialized"); status = tr("initialized");
break; break;
@ -288,7 +310,20 @@ QColor WaitTreeThread::GetColor() const {
return QColor(WaitTreeColors[2][color_index]); return QColor(WaitTreeColors[2][color_index]);
} }
case Kernel::ThreadState::Waiting: case Kernel::ThreadState::Waiting:
switch (thread.GetWaitReasonForDebugging()) {
case Kernel::ThreadWaitReasonForDebugging::IPC:
return QColor(WaitTreeColors[4][color_index]);
case Kernel::ThreadWaitReasonForDebugging::Sleep:
return QColor(WaitTreeColors[5][color_index]);
case Kernel::ThreadWaitReasonForDebugging::Synchronization:
case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
case Kernel::ThreadWaitReasonForDebugging::Arbitration:
case Kernel::ThreadWaitReasonForDebugging::Suspended:
return QColor(WaitTreeColors[6][color_index]);
break;
default:
return QColor(WaitTreeColors[3][color_index]); return QColor(WaitTreeColors[3][color_index]);
}
case Kernel::ThreadState::Initialized: case Kernel::ThreadState::Initialized:
return QColor(WaitTreeColors[7][color_index]); return QColor(WaitTreeColors[7][color_index]);
case Kernel::ThreadState::Terminated: case Kernel::ThreadState::Terminated:
@ -339,7 +374,9 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex")));
} }
if (thread.GetState() == Kernel::ThreadState::Waiting) { if (thread.GetState() == Kernel::ThreadState::Waiting &&
thread.GetWaitReasonForDebugging() ==
Kernel::ThreadWaitReasonForDebugging::Synchronization) {
list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(), list.push_back(std::make_unique<WaitTreeObjectList>(thread.GetWaitObjectsForDebugging(),
thread.IsCancellable())); thread.IsCancellable()));
} }