wait_tree.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // Copyright 2016 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "citra_qt/debugger/wait_tree.h"
  5. #include "citra_qt/util/util.h"
  6. #include "core/hle/kernel/event.h"
  7. #include "core/hle/kernel/mutex.h"
  8. #include "core/hle/kernel/semaphore.h"
  9. #include "core/hle/kernel/thread.h"
  10. #include "core/hle/kernel/timer.h"
  11. WaitTreeItem::~WaitTreeItem() {}
  12. QColor WaitTreeItem::GetColor() const {
  13. return QColor(Qt::GlobalColor::black);
  14. }
  15. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeItem::GetChildren() const {
  16. return {};
  17. }
  18. void WaitTreeItem::Expand() {
  19. if (IsExpandable() && !expanded) {
  20. children = GetChildren();
  21. for (std::size_t i = 0; i < children.size(); ++i) {
  22. children[i]->parent = this;
  23. children[i]->row = i;
  24. }
  25. expanded = true;
  26. }
  27. }
  28. WaitTreeItem* WaitTreeItem::Parent() const {
  29. return parent;
  30. }
  31. const std::vector<std::unique_ptr<WaitTreeItem>>& WaitTreeItem::Children() const {
  32. return children;
  33. }
  34. bool WaitTreeItem::IsExpandable() const {
  35. return false;
  36. }
  37. std::size_t WaitTreeItem::Row() const {
  38. return row;
  39. }
  40. std::vector<std::unique_ptr<WaitTreeThread>> WaitTreeItem::MakeThreadItemList() {
  41. const auto& threads = Kernel::GetThreadList();
  42. std::vector<std::unique_ptr<WaitTreeThread>> item_list;
  43. item_list.reserve(threads.size());
  44. for (std::size_t i = 0; i < threads.size(); ++i) {
  45. item_list.push_back(std::make_unique<WaitTreeThread>(*threads[i]));
  46. item_list.back()->row = i;
  47. }
  48. return item_list;
  49. }
  50. WaitTreeText::WaitTreeText(const QString& t) : text(t) {}
  51. QString WaitTreeText::GetText() const {
  52. return text;
  53. }
  54. WaitTreeWaitObject::WaitTreeWaitObject(const Kernel::WaitObject& o) : object(o) {}
  55. bool WaitTreeExpandableItem::IsExpandable() const {
  56. return true;
  57. }
  58. QString WaitTreeWaitObject::GetText() const {
  59. return tr("[%1]%2 %3")
  60. .arg(object.GetObjectId())
  61. .arg(QString::fromStdString(object.GetTypeName()),
  62. QString::fromStdString(object.GetName()));
  63. }
  64. std::unique_ptr<WaitTreeWaitObject> WaitTreeWaitObject::make(const Kernel::WaitObject& object) {
  65. switch (object.GetHandleType()) {
  66. case Kernel::HandleType::Event:
  67. return std::make_unique<WaitTreeEvent>(static_cast<const Kernel::Event&>(object));
  68. case Kernel::HandleType::Mutex:
  69. return std::make_unique<WaitTreeMutex>(static_cast<const Kernel::Mutex&>(object));
  70. case Kernel::HandleType::Semaphore:
  71. return std::make_unique<WaitTreeSemaphore>(static_cast<const Kernel::Semaphore&>(object));
  72. case Kernel::HandleType::Timer:
  73. return std::make_unique<WaitTreeTimer>(static_cast<const Kernel::Timer&>(object));
  74. case Kernel::HandleType::Thread:
  75. return std::make_unique<WaitTreeThread>(static_cast<const Kernel::Thread&>(object));
  76. default:
  77. return std::make_unique<WaitTreeWaitObject>(object);
  78. }
  79. }
  80. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeWaitObject::GetChildren() const {
  81. std::vector<std::unique_ptr<WaitTreeItem>> list;
  82. const auto& threads = object.GetWaitingThreads();
  83. if (threads.empty()) {
  84. list.push_back(std::make_unique<WaitTreeText>(tr("waited by no thread")));
  85. } else {
  86. list.push_back(std::make_unique<WaitTreeThreadList>(threads));
  87. }
  88. return list;
  89. }
  90. QString WaitTreeWaitObject::GetResetTypeQString(Kernel::ResetType reset_type) {
  91. switch (reset_type) {
  92. case Kernel::ResetType::OneShot:
  93. return tr("one shot");
  94. case Kernel::ResetType::Sticky:
  95. return tr("sticky");
  96. case Kernel::ResetType::Pulse:
  97. return tr("pulse");
  98. }
  99. }
  100. WaitTreeObjectList::WaitTreeObjectList(
  101. const std::vector<Kernel::SharedPtr<Kernel::WaitObject>>& list, bool w_all)
  102. : object_list(list), wait_all(w_all) {}
  103. QString WaitTreeObjectList::GetText() const {
  104. if (wait_all)
  105. return tr("waiting for all objects");
  106. return tr("waiting for one of the following objects");
  107. }
  108. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeObjectList::GetChildren() const {
  109. std::vector<std::unique_ptr<WaitTreeItem>> list(object_list.size());
  110. std::transform(object_list.begin(), object_list.end(), list.begin(),
  111. [](const auto& t) { return WaitTreeWaitObject::make(*t); });
  112. return list;
  113. }
  114. WaitTreeThread::WaitTreeThread(const Kernel::Thread& thread) : WaitTreeWaitObject(thread) {}
  115. QString WaitTreeThread::GetText() const {
  116. const auto& thread = static_cast<const Kernel::Thread&>(object);
  117. QString status;
  118. switch (thread.status) {
  119. case THREADSTATUS_RUNNING:
  120. status = tr("running");
  121. break;
  122. case THREADSTATUS_READY:
  123. status = tr("ready");
  124. break;
  125. case THREADSTATUS_WAIT_ARB:
  126. status = tr("waiting for address 0x%1").arg(thread.wait_address, 8, 16, QLatin1Char('0'));
  127. break;
  128. case THREADSTATUS_WAIT_SLEEP:
  129. status = tr("sleeping");
  130. break;
  131. case THREADSTATUS_WAIT_SYNCH:
  132. status = tr("waiting for objects");
  133. break;
  134. case THREADSTATUS_DORMANT:
  135. status = tr("dormant");
  136. break;
  137. case THREADSTATUS_DEAD:
  138. status = tr("dead");
  139. break;
  140. }
  141. QString pc_info = tr(" PC = 0x%1 LR = 0x%2")
  142. .arg(thread.context.pc, 8, 16, QLatin1Char('0'))
  143. .arg(thread.context.lr, 8, 16, QLatin1Char('0'));
  144. return WaitTreeWaitObject::GetText() + pc_info + " (" + status + ") ";
  145. }
  146. QColor WaitTreeThread::GetColor() const {
  147. const auto& thread = static_cast<const Kernel::Thread&>(object);
  148. switch (thread.status) {
  149. case THREADSTATUS_RUNNING:
  150. return QColor(Qt::GlobalColor::darkGreen);
  151. case THREADSTATUS_READY:
  152. return QColor(Qt::GlobalColor::darkBlue);
  153. case THREADSTATUS_WAIT_ARB:
  154. return QColor(Qt::GlobalColor::darkRed);
  155. case THREADSTATUS_WAIT_SLEEP:
  156. return QColor(Qt::GlobalColor::darkYellow);
  157. case THREADSTATUS_WAIT_SYNCH:
  158. return QColor(Qt::GlobalColor::red);
  159. case THREADSTATUS_DORMANT:
  160. return QColor(Qt::GlobalColor::darkCyan);
  161. case THREADSTATUS_DEAD:
  162. return QColor(Qt::GlobalColor::gray);
  163. default:
  164. return WaitTreeItem::GetColor();
  165. }
  166. }
  167. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
  168. std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
  169. const auto& thread = static_cast<const Kernel::Thread&>(object);
  170. QString processor;
  171. switch (thread.processor_id) {
  172. case ThreadProcessorId::THREADPROCESSORID_DEFAULT:
  173. processor = tr("default");
  174. break;
  175. case ThreadProcessorId::THREADPROCESSORID_ALL:
  176. processor = tr("all");
  177. break;
  178. case ThreadProcessorId::THREADPROCESSORID_0:
  179. processor = tr("AppCore");
  180. break;
  181. case ThreadProcessorId::THREADPROCESSORID_1:
  182. processor = tr("SysCore");
  183. break;
  184. default:
  185. processor = tr("Unknown processor %1").arg(thread.processor_id);
  186. break;
  187. }
  188. list.push_back(std::make_unique<WaitTreeText>(tr("processor = %1").arg(processor)));
  189. list.push_back(std::make_unique<WaitTreeText>(tr("thread id = %1").arg(thread.GetThreadId())));
  190. list.push_back(std::make_unique<WaitTreeText>(tr("priority = %1(current) / %2(normal)")
  191. .arg(thread.current_priority)
  192. .arg(thread.nominal_priority)));
  193. list.push_back(std::make_unique<WaitTreeText>(
  194. tr("last running ticks = %1").arg(thread.last_running_ticks)));
  195. if (thread.held_mutexes.empty()) {
  196. list.push_back(std::make_unique<WaitTreeText>(tr("not holding mutex")));
  197. } else {
  198. list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes));
  199. }
  200. if (thread.status == THREADSTATUS_WAIT_SYNCH) {
  201. list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, thread.wait_all));
  202. }
  203. return list;
  204. }
  205. WaitTreeEvent::WaitTreeEvent(const Kernel::Event& object) : WaitTreeWaitObject(object) {}
  206. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeEvent::GetChildren() const {
  207. std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
  208. list.push_back(std::make_unique<WaitTreeText>(
  209. tr("reset type = %1")
  210. .arg(GetResetTypeQString(static_cast<const Kernel::Event&>(object).reset_type))));
  211. return list;
  212. }
  213. WaitTreeMutex::WaitTreeMutex(const Kernel::Mutex& object) : WaitTreeWaitObject(object) {}
  214. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutex::GetChildren() const {
  215. std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
  216. const auto& mutex = static_cast<const Kernel::Mutex&>(object);
  217. if (mutex.lock_count) {
  218. list.push_back(
  219. std::make_unique<WaitTreeText>(tr("locked %1 times by thread:").arg(mutex.lock_count)));
  220. list.push_back(std::make_unique<WaitTreeThread>(*mutex.holding_thread));
  221. } else {
  222. list.push_back(std::make_unique<WaitTreeText>(tr("free")));
  223. }
  224. return list;
  225. }
  226. WaitTreeSemaphore::WaitTreeSemaphore(const Kernel::Semaphore& object)
  227. : WaitTreeWaitObject(object) {}
  228. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeSemaphore::GetChildren() const {
  229. std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
  230. const auto& semaphore = static_cast<const Kernel::Semaphore&>(object);
  231. list.push_back(
  232. std::make_unique<WaitTreeText>(tr("available count = %1").arg(semaphore.available_count)));
  233. list.push_back(std::make_unique<WaitTreeText>(tr("max count = %1").arg(semaphore.max_count)));
  234. return list;
  235. }
  236. WaitTreeTimer::WaitTreeTimer(const Kernel::Timer& object) : WaitTreeWaitObject(object) {}
  237. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeTimer::GetChildren() const {
  238. std::vector<std::unique_ptr<WaitTreeItem>> list(WaitTreeWaitObject::GetChildren());
  239. const auto& timer = static_cast<const Kernel::Timer&>(object);
  240. list.push_back(std::make_unique<WaitTreeText>(
  241. tr("reset type = %1").arg(GetResetTypeQString(timer.reset_type))));
  242. list.push_back(
  243. std::make_unique<WaitTreeText>(tr("initial delay = %1").arg(timer.initial_delay)));
  244. list.push_back(
  245. std::make_unique<WaitTreeText>(tr("interval delay = %1").arg(timer.interval_delay)));
  246. return list;
  247. }
  248. WaitTreeMutexList::WaitTreeMutexList(
  249. const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list)
  250. : mutex_list(list) {}
  251. QString WaitTreeMutexList::GetText() const {
  252. return tr("holding mutexes");
  253. }
  254. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeMutexList::GetChildren() const {
  255. std::vector<std::unique_ptr<WaitTreeItem>> list(mutex_list.size());
  256. std::transform(mutex_list.begin(), mutex_list.end(), list.begin(),
  257. [](const auto& t) { return std::make_unique<WaitTreeMutex>(*t); });
  258. return list;
  259. }
  260. WaitTreeThreadList::WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list)
  261. : thread_list(list) {}
  262. QString WaitTreeThreadList::GetText() const {
  263. return tr("waited by thread");
  264. }
  265. std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThreadList::GetChildren() const {
  266. std::vector<std::unique_ptr<WaitTreeItem>> list(thread_list.size());
  267. std::transform(thread_list.begin(), thread_list.end(), list.begin(),
  268. [](const auto& t) { return std::make_unique<WaitTreeThread>(*t); });
  269. return list;
  270. }
  271. WaitTreeModel::WaitTreeModel(QObject* parent) : QAbstractItemModel(parent) {}
  272. QModelIndex WaitTreeModel::index(int row, int column, const QModelIndex& parent) const {
  273. if (!hasIndex(row, column, parent))
  274. return {};
  275. if (parent.isValid()) {
  276. WaitTreeItem* parent_item = static_cast<WaitTreeItem*>(parent.internalPointer());
  277. parent_item->Expand();
  278. return createIndex(row, column, parent_item->Children()[row].get());
  279. }
  280. return createIndex(row, column, thread_items[row].get());
  281. }
  282. QModelIndex WaitTreeModel::parent(const QModelIndex& index) const {
  283. if (!index.isValid())
  284. return {};
  285. WaitTreeItem* parent_item = static_cast<WaitTreeItem*>(index.internalPointer())->Parent();
  286. if (!parent_item) {
  287. return QModelIndex();
  288. }
  289. return createIndex(static_cast<int>(parent_item->Row()), 0, parent_item);
  290. }
  291. int WaitTreeModel::rowCount(const QModelIndex& parent) const {
  292. if (!parent.isValid())
  293. return static_cast<int>(thread_items.size());
  294. WaitTreeItem* parent_item = static_cast<WaitTreeItem*>(parent.internalPointer());
  295. parent_item->Expand();
  296. return static_cast<int>(parent_item->Children().size());
  297. }
  298. int WaitTreeModel::columnCount(const QModelIndex&) const {
  299. return 1;
  300. }
  301. QVariant WaitTreeModel::data(const QModelIndex& index, int role) const {
  302. if (!index.isValid())
  303. return {};
  304. switch (role) {
  305. case Qt::DisplayRole:
  306. return static_cast<WaitTreeItem*>(index.internalPointer())->GetText();
  307. case Qt::ForegroundRole:
  308. return static_cast<WaitTreeItem*>(index.internalPointer())->GetColor();
  309. default:
  310. return {};
  311. }
  312. }
  313. void WaitTreeModel::ClearItems() {
  314. thread_items.clear();
  315. }
  316. void WaitTreeModel::InitItems() {
  317. thread_items = WaitTreeItem::MakeThreadItemList();
  318. }
  319. WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("Wait Tree"), parent) {
  320. setObjectName("WaitTreeWidget");
  321. view = new QTreeView(this);
  322. view->setHeaderHidden(true);
  323. setWidget(view);
  324. setEnabled(false);
  325. }
  326. void WaitTreeWidget::OnDebugModeEntered() {
  327. if (!Core::g_app_core)
  328. return;
  329. model->InitItems();
  330. view->setModel(model);
  331. setEnabled(true);
  332. }
  333. void WaitTreeWidget::OnDebugModeLeft() {
  334. setEnabled(false);
  335. view->setModel(nullptr);
  336. model->ClearItems();
  337. }
  338. void WaitTreeWidget::OnEmulationStarting(EmuThread* emu_thread) {
  339. model = new WaitTreeModel(this);
  340. view->setModel(model);
  341. setEnabled(false);
  342. }
  343. void WaitTreeWidget::OnEmulationStopping() {
  344. view->setModel(nullptr);
  345. delete model;
  346. setEnabled(false);
  347. }