mirror of
				https://github.com/yuzu-emu/yuzu.git
				synced 2025-10-31 20:52:48 +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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Subv
						Subv