|
|
@ -6,8 +6,8 @@ |
|
|
#include "yuzu/util/util.h"
|
|
|
#include "yuzu/util/util.h"
|
|
|
|
|
|
|
|
|
#include "core/core.h"
|
|
|
#include "core/core.h"
|
|
|
#include "core/hle/kernel/condition_variable.h"
|
|
|
|
|
|
#include "core/hle/kernel/event.h"
|
|
|
#include "core/hle/kernel/event.h"
|
|
|
|
|
|
#include "core/hle/kernel/handle_table.h"
|
|
|
#include "core/hle/kernel/mutex.h"
|
|
|
#include "core/hle/kernel/mutex.h"
|
|
|
#include "core/hle/kernel/thread.h"
|
|
|
#include "core/hle/kernel/thread.h"
|
|
|
#include "core/hle/kernel/timer.h"
|
|
|
#include "core/hle/kernel/timer.h"
|
|
|
@ -67,6 +67,29 @@ QString WaitTreeText::GetText() const { |
|
|
return text; |
|
|
return text; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) { |
|
|
|
|
|
mutex_value = Memory::Read32(mutex_address); |
|
|
|
|
|
owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask); |
|
|
|
|
|
owner = Kernel::g_handle_table.Get<Kernel::Thread>(owner_handle); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
QString WaitTreeMutexInfo::GetText() const { |
|
|
|
|
|
return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char('0')); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() const { |
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> list; |
|
|
|
|
|
|
|
|
|
|
|
bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0; |
|
|
|
|
|
|
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>(tr("has waiters: %1").arg(has_waiters))); |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>( |
|
|
|
|
|
tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char('0')))); |
|
|
|
|
|
if (owner != nullptr) |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeThread>(*owner)); |
|
|
|
|
|
return list; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} |
|
|
WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} |
|
|
|
|
|
|
|
|
bool WaitTreeExpandableItem::IsExpandable() const { |
|
|
bool WaitTreeExpandableItem::IsExpandable() const { |
|
|
@ -84,11 +107,6 @@ std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitO |
|
|
switch (object.GetHandleType()) { |
|
|
switch (object.GetHandleType()) { |
|
|
case Kernel::HandleType::Event: |
|
|
case Kernel::HandleType::Event: |
|
|
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); |
|
|
return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); |
|
|
case Kernel::HandleType::Mutex: |
|
|
|
|
|
return std::make_unique<WaitTreeMutex>(static_cast<const Kernel::Mutex&>(object)); |
|
|
|
|
|
case Kernel::HandleType::ConditionVariable: |
|
|
|
|
|
return std::make_unique<WaitTreeConditionVariable>( |
|
|
|
|
|
static_cast<const Kernel::ConditionVariable&>(object)); |
|
|
|
|
|
case Kernel::HandleType::Timer: |
|
|
case Kernel::HandleType::Timer: |
|
|
return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); |
|
|
return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); |
|
|
case Kernel::HandleType::Thread: |
|
|
case Kernel::HandleType::Thread: |
|
|
@ -160,6 +178,9 @@ QString WaitTreeThread::GetText() const { |
|
|
case THREADSTATUS_WAIT_SYNCH_ANY: |
|
|
case THREADSTATUS_WAIT_SYNCH_ANY: |
|
|
status = tr("waiting for objects"); |
|
|
status = tr("waiting for objects"); |
|
|
break; |
|
|
break; |
|
|
|
|
|
case THREADSTATUS_WAIT_MUTEX: |
|
|
|
|
|
status = tr("waiting for mutex"); |
|
|
|
|
|
break; |
|
|
case THREADSTATUS_DORMANT: |
|
|
case THREADSTATUS_DORMANT: |
|
|
status = tr("dormant"); |
|
|
status = tr("dormant"); |
|
|
break; |
|
|
break; |
|
|
@ -186,6 +207,7 @@ QColor WaitTreeThread::GetColor() const { |
|
|
return QColor(Qt::GlobalColor::darkYellow); |
|
|
return QColor(Qt::GlobalColor::darkYellow); |
|
|
case THREADSTATUS_WAIT_SYNCH_ALL: |
|
|
case THREADSTATUS_WAIT_SYNCH_ALL: |
|
|
case THREADSTATUS_WAIT_SYNCH_ANY: |
|
|
case THREADSTATUS_WAIT_SYNCH_ANY: |
|
|
|
|
|
case THREADSTATUS_WAIT_MUTEX: |
|
|
return QColor(Qt::GlobalColor::red); |
|
|
return QColor(Qt::GlobalColor::red); |
|
|
case THREADSTATUS_DORMANT: |
|
|
case THREADSTATUS_DORMANT: |
|
|
return QColor(Qt::GlobalColor::darkCyan); |
|
|
return QColor(Qt::GlobalColor::darkCyan); |
|
|
@ -225,11 +247,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { |
|
|
list.push_back(std::make_unique<WaitTreeText>( |
|
|
list.push_back(std::make_unique<WaitTreeText>( |
|
|
tr("last running ticks = %1").arg(thread.last_running_ticks))); |
|
|
tr("last running ticks = %1").arg(thread.last_running_ticks))); |
|
|
|
|
|
|
|
|
if (thread.held_mutexes.empty()) { |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>(tr("not holding mutex"))); |
|
|
|
|
|
} else { |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (thread.mutex_wait_address != 0) |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeMutexInfo>(thread.mutex_wait_address)); |
|
|
|
|
|
else |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); |
|
|
|
|
|
|
|
|
if (thread.status == THREADSTATUS_WAIT_SYNCH_ANY || |
|
|
if (thread.status == THREADSTATUS_WAIT_SYNCH_ANY || |
|
|
thread.status == THREADSTATUS_WAIT_SYNCH_ALL) { |
|
|
thread.status == THREADSTATUS_WAIT_SYNCH_ALL) { |
|
|
list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, |
|
|
list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, |
|
|
@ -250,33 +272,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const { |
|
|
return list; |
|
|
return list; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
WaitTreeMutex::WaitTreeMutex(const Kernel::Mutex& object) : WaitTreeWaitObject(object) {} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutex::GetChildren() const { |
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren()); |
|
|
|
|
|
|
|
|
|
|
|
const auto& mutex = static_cast<const Kernel::Mutex&>(object); |
|
|
|
|
|
if (mutex.GetHasWaiters()) { |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>(tr("locked by thread:"))); |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeThread>(*mutex.GetHoldingThread())); |
|
|
|
|
|
} else { |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>(tr("free"))); |
|
|
|
|
|
} |
|
|
|
|
|
return list; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WaitTreeConditionVariable::WaitTreeConditionVariable(const Kernel::ConditionVariable& object) |
|
|
|
|
|
: WaitTreeWaitObject(object) {} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeConditionVariable::GetChildren() const { |
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren()); |
|
|
|
|
|
|
|
|
|
|
|
const auto& condition_variable = static_cast<const Kernel::ConditionVariable&>(object); |
|
|
|
|
|
list.push_back(std::make_unique<WaitTreeText>( |
|
|
|
|
|
tr("available count = %1").arg(condition_variable.GetAvailableCount()))); |
|
|
|
|
|
return list; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WaitTreeTimer::WaitTreeTimer(const Kernel::Timer& object) : WaitTreeWaitObject(object) {} |
|
|
WaitTreeTimer::WaitTreeTimer(const Kernel::Timer& object) : WaitTreeWaitObject(object) {} |
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { |
|
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { |
|
|
@ -293,21 +288,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { |
|
|
return list; |
|
|
return list; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
WaitTreeMutexList::WaitTreeMutexList( |
|
|
|
|
|
const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list) |
|
|
|
|
|
: mutex_list(list) {} |
|
|
|
|
|
|
|
|
|
|
|
QString WaitTreeMutexList::GetText() const { |
|
|
|
|
|
return tr("holding mutexes"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexList::GetChildren() const { |
|
|
|
|
|
std::vector<std::unique_ptr<WaitTreeItem>> list(mutex_list.size()); |
|
|
|
|
|
std::transform(mutex_list.begin(), mutex_list.end(), list.begin(), |
|
|
|
|
|
[](const auto& t) { return std::make_unique<WaitTreeMutex>(*t); }); |
|
|
|
|
|
return list; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list) |
|
|
WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list) |
|
|
: thread_list(list) {} |
|
|
: thread_list(list) {} |
|
|
|
|
|
|
|
|
|