diff options
| author | 2018-04-20 15:52:06 -0500 | |
|---|---|---|
| committer | 2018-04-20 21:04:34 -0500 | |
| commit | 013778aa21bad3769b739d14843b8ef2bb3185c9 (patch) | |
| tree | 4d338fcd6a19a4d0c3d4f0d604c3dd82c3111557 /src | |
| parent | Kernel: Remove unused ConditionVariable class. (diff) | |
| download | yuzu-013778aa21bad3769b739d14843b8ef2bb3185c9.tar.gz yuzu-013778aa21bad3769b739d14843b8ef2bb3185c9.tar.xz yuzu-013778aa21bad3769b739d14843b8ef2bb3185c9.zip | |
Qt: Update the WaitTree widget to show info about the current mutex of each thread.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.cpp | 6 | ||||
| -rw-r--r-- | src/core/hle/service/nvflinger/buffer_queue.h | 6 | ||||
| -rw-r--r-- | src/yuzu/debugger/wait_tree.cpp | 86 | ||||
| -rw-r--r-- | 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; | |||
| 18 | enum class HandleType : u32 { | 18 | enum class HandleType : u32 { |
| 19 | Unknown, | 19 | Unknown, |
| 20 | Event, | 20 | Event, |
| 21 | Mutex, | ||
| 22 | SharedMemory, | 21 | SharedMemory, |
| 23 | Thread, | 22 | Thread, |
| 24 | Process, | 23 | Process, |
| 25 | AddressArbiter, | 24 | AddressArbiter, |
| 26 | ConditionVariable, | ||
| 27 | Timer, | 25 | Timer, |
| 28 | ResourceLimit, | 26 | ResourceLimit, |
| 29 | CodeSet, | 27 | CodeSet, |
| @@ -63,9 +61,7 @@ public: | |||
| 63 | bool IsWaitable() const { | 61 | bool IsWaitable() const { |
| 64 | switch (GetHandleType()) { | 62 | switch (GetHandleType()) { |
| 65 | case HandleType::Event: | 63 | case HandleType::Event: |
| 66 | case HandleType::Mutex: | ||
| 67 | case HandleType::Thread: | 64 | case HandleType::Thread: |
| 68 | case HandleType::ConditionVariable: | ||
| 69 | case HandleType::Timer: | 65 | case HandleType::Timer: |
| 70 | case HandleType::ServerPort: | 66 | case HandleType::ServerPort: |
| 71 | case HandleType::ServerSession: | 67 | 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 @@ | |||
| 9 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 10 | #include "core/hle/service/nvflinger/buffer_queue.h" | 10 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 11 | 11 | ||
| 12 | namespace Service::NVFlinger { | 12 | namespace Service { |
| 13 | namespace NVFlinger { | ||
| 13 | 14 | ||
| 14 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | 15 | BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { |
| 15 | native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); | 16 | native_handle = Kernel::Event::Create(Kernel::ResetType::OneShot, "BufferQueue NativeHandle"); |
| @@ -110,4 +111,5 @@ void BufferQueue::SetBufferWaitEvent(Kernel::SharedPtr<Kernel::Event>&& wait_eve | |||
| 110 | buffer_wait_event = std::move(wait_event); | 111 | buffer_wait_event = std::move(wait_event); |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | } // namespace Service::NVFlinger | 114 | } // namespace NVFlinger |
| 115 | } // 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 { | |||
| 13 | struct EventType; | 13 | struct EventType; |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | namespace Service::NVFlinger { | 16 | namespace Service { |
| 17 | namespace NVFlinger { | ||
| 17 | 18 | ||
| 18 | struct IGBPBuffer { | 19 | struct IGBPBuffer { |
| 19 | u32_le magic; | 20 | u32_le magic; |
| @@ -97,4 +98,5 @@ private: | |||
| 97 | Kernel::SharedPtr<Kernel::Event> buffer_wait_event; | 98 | Kernel::SharedPtr<Kernel::Event> buffer_wait_event; |
| 98 | }; | 99 | }; |
| 99 | 100 | ||
| 100 | } // namespace Service::NVFlinger | 101 | } // namespace NVFlinger |
| 102 | } // 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 @@ | |||
| 6 | #include "yuzu/util/util.h" | 6 | #include "yuzu/util/util.h" |
| 7 | 7 | ||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/kernel/condition_variable.h" | ||
| 10 | #include "core/hle/kernel/event.h" | 9 | #include "core/hle/kernel/event.h" |
| 10 | #include "core/hle/kernel/handle_table.h" | ||
| 11 | #include "core/hle/kernel/mutex.h" | 11 | #include "core/hle/kernel/mutex.h" |
| 12 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 13 | #include "core/hle/kernel/timer.h" | 13 | #include "core/hle/kernel/timer.h" |
| @@ -67,6 +67,29 @@ QString WaitTreeText::GetText() const { | |||
| 67 | return text; | 67 | return text; |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) { | ||
| 71 | mutex_value = Memory::Read32(mutex_address); | ||
| 72 | owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask); | ||
| 73 | owner = Kernel::g_handle_table.Get<Kernel::Thread>(owner_handle); | ||
| 74 | } | ||
| 75 | |||
| 76 | QString WaitTreeMutexInfo::GetText() const { | ||
| 77 | return tr("waiting for mutex 0x%1").arg(mutex_address, 16, 16, QLatin1Char('0')); | ||
| 78 | } | ||
| 79 | |||
| 80 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexInfo::GetChildren() const { | ||
| 81 | std::vector<std::unique_ptr<WaitTreeItem>> list; | ||
| 82 | |||
| 83 | bool has_waiters = (mutex_value & Kernel::Mutex::MutexHasWaitersFlag) != 0; | ||
| 84 | |||
| 85 | list.push_back(std::make_unique<WaitTreeText>(tr("has waiters: %1").arg(has_waiters))); | ||
| 86 | list.push_back(std::make_unique<WaitTreeText>( | ||
| 87 | tr("owner handle: 0x%1").arg(owner_handle, 8, 16, QLatin1Char('0')))); | ||
| 88 | if (owner != nullptr) | ||
| 89 | list.push_back(std::make_unique<WaitTreeThread>(*owner)); | ||
| 90 | return list; | ||
| 91 | } | ||
| 92 | |||
| 70 | WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} | 93 | WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {} |
| 71 | 94 | ||
| 72 | bool WaitTreeExpandableItem::IsExpandable() const { | 95 | bool WaitTreeExpandableItem::IsExpandable() const { |
| @@ -84,11 +107,6 @@ std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitO | |||
| 84 | switch (object.GetHandleType()) { | 107 | switch (object.GetHandleType()) { |
| 85 | case Kernel::HandleType::Event: | 108 | case Kernel::HandleType::Event: |
| 86 | return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); | 109 | return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object)); |
| 87 | case Kernel::HandleType::Mutex: | ||
| 88 | return std::make_unique<WaitTreeMutex>(static_cast<const Kernel::Mutex&>(object)); | ||
| 89 | case Kernel::HandleType::ConditionVariable: | ||
| 90 | return std::make_unique<WaitTreeConditionVariable>( | ||
| 91 | static_cast<const Kernel::ConditionVariable&>(object)); | ||
| 92 | case Kernel::HandleType::Timer: | 110 | case Kernel::HandleType::Timer: |
| 93 | return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); | 111 | return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object)); |
| 94 | case Kernel::HandleType::Thread: | 112 | case Kernel::HandleType::Thread: |
| @@ -160,6 +178,9 @@ QString WaitTreeThread::GetText() const { | |||
| 160 | case THREADSTATUS_WAIT_SYNCH_ANY: | 178 | case THREADSTATUS_WAIT_SYNCH_ANY: |
| 161 | status = tr("waiting for objects"); | 179 | status = tr("waiting for objects"); |
| 162 | break; | 180 | break; |
| 181 | case THREADSTATUS_WAIT_MUTEX: | ||
| 182 | status = tr("waiting for mutex"); | ||
| 183 | break; | ||
| 163 | case THREADSTATUS_DORMANT: | 184 | case THREADSTATUS_DORMANT: |
| 164 | status = tr("dormant"); | 185 | status = tr("dormant"); |
| 165 | break; | 186 | break; |
| @@ -186,6 +207,7 @@ QColor WaitTreeThread::GetColor() const { | |||
| 186 | return QColor(Qt::GlobalColor::darkYellow); | 207 | return QColor(Qt::GlobalColor::darkYellow); |
| 187 | case THREADSTATUS_WAIT_SYNCH_ALL: | 208 | case THREADSTATUS_WAIT_SYNCH_ALL: |
| 188 | case THREADSTATUS_WAIT_SYNCH_ANY: | 209 | case THREADSTATUS_WAIT_SYNCH_ANY: |
| 210 | case THREADSTATUS_WAIT_MUTEX: | ||
| 189 | return QColor(Qt::GlobalColor::red); | 211 | return QColor(Qt::GlobalColor::red); |
| 190 | case THREADSTATUS_DORMANT: | 212 | case THREADSTATUS_DORMANT: |
| 191 | return QColor(Qt::GlobalColor::darkCyan); | 213 | return QColor(Qt::GlobalColor::darkCyan); |
| @@ -225,11 +247,11 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const { | |||
| 225 | list.push_back(std::make_unique<WaitTreeText>( | 247 | list.push_back(std::make_unique<WaitTreeText>( |
| 226 | tr("last running ticks = %1").arg(thread.last_running_ticks))); | 248 | tr("last running ticks = %1").arg(thread.last_running_ticks))); |
| 227 | 249 | ||
| 228 | if (thread.held_mutexes.empty()) { | 250 | if (thread.mutex_wait_address != 0) |
| 229 | list.push_back(std::make_unique<WaitTreeText>(tr("not holding mutex"))); | 251 | list.push_back(std::make_unique<WaitTreeMutexInfo>(thread.mutex_wait_address)); |
| 230 | } else { | 252 | else |
| 231 | list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes)); | 253 | list.push_back(std::make_unique<WaitTreeText>(tr("not waiting for mutex"))); |
| 232 | } | 254 | |
| 233 | if (thread.status == THREADSTATUS_WAIT_SYNCH_ANY || | 255 | if (thread.status == THREADSTATUS_WAIT_SYNCH_ANY || |
| 234 | thread.status == THREADSTATUS_WAIT_SYNCH_ALL) { | 256 | thread.status == THREADSTATUS_WAIT_SYNCH_ALL) { |
| 235 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, | 257 | list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, |
| @@ -250,33 +272,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const { | |||
| 250 | return list; | 272 | return list; |
| 251 | } | 273 | } |
| 252 | 274 | ||
| 253 | WaitTreeMutex::WaitTreeMutex(const Kernel::Mutex& object) : WaitTreeWaitObject(object) {} | ||
| 254 | |||
| 255 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutex::GetChildren() const { | ||
| 256 | std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren()); | ||
| 257 | |||
| 258 | const auto& mutex = static_cast<const Kernel::Mutex&>(object); | ||
| 259 | if (mutex.GetHasWaiters()) { | ||
| 260 | list.push_back(std::make_unique<WaitTreeText>(tr("locked by thread:"))); | ||
| 261 | list.push_back(std::make_unique<WaitTreeThread>(*mutex.GetHoldingThread())); | ||
| 262 | } else { | ||
| 263 | list.push_back(std::make_unique<WaitTreeText>(tr("free"))); | ||
| 264 | } | ||
| 265 | return list; | ||
| 266 | } | ||
| 267 | |||
| 268 | WaitTreeConditionVariable::WaitTreeConditionVariable(const Kernel::ConditionVariable& object) | ||
| 269 | : WaitTreeWaitObject(object) {} | ||
| 270 | |||
| 271 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeConditionVariable::GetChildren() const { | ||
| 272 | std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren()); | ||
| 273 | |||
| 274 | const auto& condition_variable = static_cast<const Kernel::ConditionVariable&>(object); | ||
| 275 | list.push_back(std::make_unique<WaitTreeText>( | ||
| 276 | tr("available count = %1").arg(condition_variable.GetAvailableCount()))); | ||
| 277 | return list; | ||
| 278 | } | ||
| 279 | |||
| 280 | WaitTreeTimer::WaitTreeTimer(const Kernel::Timer& object) : WaitTreeWaitObject(object) {} | 275 | WaitTreeTimer::WaitTreeTimer(const Kernel::Timer& object) : WaitTreeWaitObject(object) {} |
| 281 | 276 | ||
| 282 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { | 277 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { |
| @@ -293,21 +288,6 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const { | |||
| 293 | return list; | 288 | return list; |
| 294 | } | 289 | } |
| 295 | 290 | ||
| 296 | WaitTreeMutexList::WaitTreeMutexList( | ||
| 297 | const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list) | ||
| 298 | : mutex_list(list) {} | ||
| 299 | |||
| 300 | QString WaitTreeMutexList::GetText() const { | ||
| 301 | return tr("holding mutexes"); | ||
| 302 | } | ||
| 303 | |||
| 304 | std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexList::GetChildren() const { | ||
| 305 | std::vector<std::unique_ptr<WaitTreeItem>> list(mutex_list.size()); | ||
| 306 | std::transform(mutex_list.begin(), mutex_list.end(), list.begin(), | ||
| 307 | [](const auto& t) { return std::make_unique<WaitTreeMutex>(*t); }); | ||
| 308 | return list; | ||
| 309 | } | ||
| 310 | |||
| 311 | WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list) | 291 | WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list) |
| 312 | : thread_list(list) {} | 292 | : thread_list(list) {} |
| 313 | 293 | ||
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; | |||
| 16 | namespace Kernel { | 16 | namespace Kernel { |
| 17 | class WaitObject; | 17 | class WaitObject; |
| 18 | class Event; | 18 | class Event; |
| 19 | class Mutex; | ||
| 20 | class ConditionVariable; | ||
| 21 | class Thread; | 19 | class Thread; |
| 22 | class Timer; | 20 | class Timer; |
| 23 | } // namespace Kernel | 21 | } // namespace Kernel |
| @@ -61,6 +59,20 @@ public: | |||
| 61 | bool IsExpandable() const override; | 59 | bool IsExpandable() const override; |
| 62 | }; | 60 | }; |
| 63 | 61 | ||
| 62 | class WaitTreeMutexInfo : public WaitTreeExpandableItem { | ||
| 63 | Q_OBJECT | ||
| 64 | public: | ||
| 65 | explicit WaitTreeMutexInfo(VAddr mutex_address); | ||
| 66 | QString GetText() const override; | ||
| 67 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | ||
| 68 | |||
| 69 | private: | ||
| 70 | VAddr mutex_address; | ||
| 71 | u32 mutex_value; | ||
| 72 | Kernel::Handle owner_handle; | ||
| 73 | Kernel::SharedPtr<Kernel::Thread> owner; | ||
| 74 | }; | ||
| 75 | |||
| 64 | class WaitTreeWaitObject : public WaitTreeExpandableItem { | 76 | class WaitTreeWaitObject : public WaitTreeExpandableItem { |
| 65 | Q_OBJECT | 77 | Q_OBJECT |
| 66 | public: | 78 | public: |
| @@ -104,20 +116,6 @@ public: | |||
| 104 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 116 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 105 | }; | 117 | }; |
| 106 | 118 | ||
| 107 | class WaitTreeMutex : public WaitTreeWaitObject { | ||
| 108 | Q_OBJECT | ||
| 109 | public: | ||
| 110 | explicit WaitTreeMutex(const Kernel::Mutex& object); | ||
| 111 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | ||
| 112 | }; | ||
| 113 | |||
| 114 | class WaitTreeConditionVariable : public WaitTreeWaitObject { | ||
| 115 | Q_OBJECT | ||
| 116 | public: | ||
| 117 | explicit WaitTreeConditionVariable(const Kernel::ConditionVariable& object); | ||
| 118 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | ||
| 119 | }; | ||
| 120 | |||
| 121 | class WaitTreeTimer : public WaitTreeWaitObject { | 119 | class WaitTreeTimer : public WaitTreeWaitObject { |
| 122 | Q_OBJECT | 120 | Q_OBJECT |
| 123 | public: | 121 | public: |
| @@ -125,19 +123,6 @@ public: | |||
| 125 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | 123 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; |
| 126 | }; | 124 | }; |
| 127 | 125 | ||
| 128 | class WaitTreeMutexList : public WaitTreeExpandableItem { | ||
| 129 | Q_OBJECT | ||
| 130 | public: | ||
| 131 | explicit WaitTreeMutexList( | ||
| 132 | const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list); | ||
| 133 | |||
| 134 | QString GetText() const override; | ||
| 135 | std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override; | ||
| 136 | |||
| 137 | private: | ||
| 138 | const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& mutex_list; | ||
| 139 | }; | ||
| 140 | |||
| 141 | class WaitTreeThreadList : public WaitTreeExpandableItem { | 126 | class WaitTreeThreadList : public WaitTreeExpandableItem { |
| 142 | Q_OBJECT | 127 | Q_OBJECT |
| 143 | public: | 128 | public: |