mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Qt: Update the WaitTree widget to show info about the current mutex of each thread.
This commit is contained in:
		
							parent
							
								
									be155f4d9d
								
							
						
					
					
						commit
						013778aa21
					
				@ -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:
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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) {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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:
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user