From 013778aa21bad3769b739d14843b8ef2bb3185c9 Mon Sep 17 00:00:00 2001
From: Subv <subv2112@gmail.com>
Date: Fri, 20 Apr 2018 15:52:06 -0500
Subject: [PATCH] Qt: Update the WaitTree widget to show info about the current
 mutex of each thread.

---
 src/core/hle/kernel/kernel.h                  |  4 -
 .../hle/service/nvflinger/buffer_queue.cpp    |  6 +-
 src/core/hle/service/nvflinger/buffer_queue.h |  6 +-
 src/yuzu/debugger/wait_tree.cpp               | 86 +++++++------------
 src/yuzu/debugger/wait_tree.h                 | 43 +++-------
 5 files changed, 55 insertions(+), 90 deletions(-)

diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 053bf4e17..402ae900f 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -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:
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp
index 03a4fed59..e4ff2e267 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.cpp
+++ b/src/core/hle/service/nvflinger/buffer_queue.cpp
@@ -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
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h
index 95adc4706..1de5767cb 100644
--- a/src/core/hle/service/nvflinger/buffer_queue.h
+++ b/src/core/hle/service/nvflinger/buffer_queue.h
@@ -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
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index cae2864e5..acc4c2e0b 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -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) {}
 
diff --git a/src/yuzu/debugger/wait_tree.h b/src/yuzu/debugger/wait_tree.h
index e538174eb..300ba9ae4 100644
--- a/src/yuzu/debugger/wait_tree.h
+++ b/src/yuzu/debugger/wait_tree.h
@@ -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: