mirror of
https://github.com/yuzu-emu/yuzu-android
synced 2024-12-25 20:51:20 -08:00
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:
parent
81c1bfafea
commit
03dfc8d8e7
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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};
|
||||||
|
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user