Qt: Update the WaitTree widget to show info about the current mutex of each thread.
This commit is contained in:
parent
be155f4d9d
commit
013778aa21
5 changed files with 55 additions and 90 deletions
|
@ -18,12 +18,10 @@ using Handle = u32;
|
||||||
enum class HandleType : u32 {
|
enum class HandleType : u32 {
|
||||||
Unknown,
|
Unknown,
|
||||||
Event,
|
Event,
|
||||||
Mutex,
|
|
||||||
SharedMemory,
|
SharedMemory,
|
||||||
Thread,
|
Thread,
|
||||||
Process,
|
Process,
|
||||||
AddressArbiter,
|
AddressArbiter,
|
||||||
ConditionVariable,
|
|
||||||
Timer,
|
Timer,
|
||||||
ResourceLimit,
|
ResourceLimit,
|
||||||
CodeSet,
|
CodeSet,
|
||||||
|
@ -63,9 +61,7 @@ public:
|
||||||
bool IsWaitable() const {
|
bool IsWaitable() const {
|
||||||
switch (GetHandleType()) {
|
switch (GetHandleType()) {
|
||||||
case HandleType::Event:
|
case HandleType::Event:
|
||||||
case HandleType::Mutex:
|
|
||||||
case HandleType::Thread:
|
case HandleType::Thread:
|
||||||
case HandleType::ConditionVariable:
|
|
||||||
case HandleType::Timer:
|
case HandleType::Timer:
|
||||||
case HandleType::ServerPort:
|
case HandleType::ServerPort:
|
||||||
case HandleType::ServerSession:
|
case HandleType::ServerSession:
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "core/hle/service/nvflinger/buffer_queue.h"
|
#include "core/hle/service/nvflinger/buffer_queue.h"
|
||||||
|
|
||||||
namespace Service::NVFlinger {
|
namespace Service {
|
||||||
|
namespace NVFlinger {
|
||||||
|
|
||||||
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
|
BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) {
|
||||||
native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
|
native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle");
|
||||||
|
@ -110,4 +111,5 @@ void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_eve
|
||||||
buffer_wait_event = std::move(wait_event);
|
buffer_wait_event = std::move(wait_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::NVFlinger
|
} // namespace NVFlinger
|
||||||
|
} // namespace Service
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace CoreTiming {
|
||||||
struct EventType;
|
struct EventType;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Service::NVFlinger {
|
namespace Service {
|
||||||
|
namespace NVFlinger {
|
||||||
|
|
||||||
struct IGBPBuffer {
|
struct IGBPBuffer {
|
||||||
u32_le magic;
|
u32_le magic;
|
||||||
|
@ -97,4 +98,5 @@ private:
|
||||||
Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
|
Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Service::NVFlinger
|
} // namespace NVFlinger
|
||||||
|
} // namespace Service
|
||||||
|
|
|
@ -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()) {
|
if (thread.mutex_wait_address != 0)
|
||||||
list.push_back(std::make_unique<WaitTreeText>(tr("not holding mutex")));
|
list.push_back(std::make_unique<WaitTreeMutexInfo>(thread.mutex_wait_address));
|
||||||
} else {
|
else
|
||||||
list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes));
|
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) {}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ class EmuThread;
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class WaitObject;
|
class WaitObject;
|
||||||
class Event;
|
class Event;
|
||||||
class Mutex;
|
|
||||||
class ConditionVariable;
|
|
||||||
class Thread;
|
class Thread;
|
||||||
class Timer;
|
class Timer;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
@ -61,6 +59,20 @@ public:
|
||||||
bool IsExpandable() const override;
|
bool IsExpandable() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WaitTreeMutexInfo : public WaitTreeExpandableItem {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit WaitTreeMutexInfo(VAddr mutex_address);
|
||||||
|
QString GetText() const override;
|
||||||
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VAddr mutex_address;
|
||||||
|
u32 mutex_value;
|
||||||
|
Kernel::Handle owner_handle;
|
||||||
|
Kernel::SharedPtr<Kernel::Thread> owner;
|
||||||
|
};
|
||||||
|
|
||||||
class WaitTreeWaitObject : public WaitTreeExpandableItem {
|
class WaitTreeWaitObject : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -104,20 +116,6 @@ public:
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeMutex : public WaitTreeWaitObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WaitTreeMutex(const Kernel::Mutex& object);
|
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WaitTreeConditionVariable : public WaitTreeWaitObject {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WaitTreeConditionVariable(const Kernel::ConditionVariable& object);
|
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WaitTreeTimer : public WaitTreeWaitObject {
|
class WaitTreeTimer : public WaitTreeWaitObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -125,19 +123,6 @@ public:
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitTreeMutexList : public WaitTreeExpandableItem {
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WaitTreeMutexList(
|
|
||||||
const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list);
|
|
||||||
|
|
||||||
QString GetText() const override;
|
|
||||||
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& mutex_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
class WaitTreeThreadList : public WaitTreeExpandableItem {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Reference in a new issue