Qt: Update the WaitTree widget to show info about the current mutex of each thread.

This commit is contained in:
Subv 2018-04-20 15:52:06 -05:00
parent be155f4d9d
commit 013778aa21
5 changed files with 55 additions and 90 deletions

View file

@ -18,12 +18,10 @@ using Handle = u32;
enum class HandleType : u32 {
Unknown,
Event,
Mutex,
SharedMemory,
Thread,
Process,
AddressArbiter,
ConditionVariable,
Timer,
ResourceLimit,
CodeSet,
@ -63,9 +61,7 @@ public:
bool IsWaitable() const {
switch (GetHandleType()) {
case HandleType::Event:
case HandleType::Mutex:
case HandleType::Thread:
case HandleType::ConditionVariable:
case HandleType::Timer:
case HandleType::ServerPort:
case HandleType::ServerSession:

View file

@ -9,7 +9,8 @@
#include "core/core_timing.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) {
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);
}
} // namespace Service::NVFlinger
} // namespace NVFlinger
} // namespace Service

View file

@ -13,7 +13,8 @@ namespace CoreTiming {
struct EventType;
}
namespace Service::NVFlinger {
namespace Service {
namespace NVFlinger {
struct IGBPBuffer {
u32_le magic;
@ -97,4 +98,5 @@ private:
Kernel::SharedPtr<Kernel::Event> buffer_wait_event;
};
} // namespace Service::NVFlinger
} // namespace NVFlinger
} // namespace Service

View file

@ -6,8 +6,8 @@
#include "yuzu/util/util.h"
#include "core/core.h"
#include "core/hle/kernel/condition_variable.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@ -67,6 +67,29 @@ QString WaitTreeText::GetText() const {
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) {}
bool WaitTreeExpandableItem::IsExpandable() const {
@ -84,11 +107,6 @@ std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitO
switch (object.GetHandleType()) {
case Kernel::HandleType::Event:
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:
return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object));
case Kernel::HandleType::Thread:
@ -160,6 +178,9 @@ QString WaitTreeThread::GetText() const {
case THREADSTATUS_WAIT_SYNCH_ANY:
status = tr("waiting for objects");
break;
case THREADSTATUS_WAIT_MUTEX:
status = tr("waiting for mutex");
break;
case THREADSTATUS_DORMANT:
status = tr("dormant");
break;
@ -186,6 +207,7 @@ QColor WaitTreeThread::GetColor() const {
return QColor(Qt::GlobalColor::darkYellow);
case THREADSTATUS_WAIT_SYNCH_ALL:
case THREADSTATUS_WAIT_SYNCH_ANY:
case THREADSTATUS_WAIT_MUTEX:
return QColor(Qt::GlobalColor::red);
case THREADSTATUS_DORMANT:
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>(
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 ||
thread.status == THREADSTATUS_WAIT_SYNCH_ALL) {
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;
}
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) {}
std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const {
@ -293,21 +288,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const {
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)
: thread_list(list) {}

View file

@ -16,8 +16,6 @@ class EmuThread;
namespace Kernel {
class WaitObject;
class Event;
class Mutex;
class ConditionVariable;
class Thread;
class Timer;
} // namespace Kernel
@ -61,6 +59,20 @@ public:
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 {
Q_OBJECT
public:
@ -104,20 +116,6 @@ public:
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 {
Q_OBJECT
public:
@ -125,19 +123,6 @@ public:
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 {
Q_OBJECT
public: