From 9385f0673bc676e88c739c33724847cc1a1616b2 Mon Sep 17 00:00:00 2001 From: Elad Ashkenazi <18193363+elad335@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:59:44 +0300 Subject: [PATCH] Debugger: Non-blocking thread list refresh --- rpcs3/rpcs3qt/debugger_frame.cpp | 78 ++++++++++++++++++++++---------- rpcs3/rpcs3qt/debugger_frame.h | 2 + rpcs3/rpcs3qt/debugger_list.cpp | 14 +++--- 3 files changed, 62 insertions(+), 32 deletions(-) diff --git a/rpcs3/rpcs3qt/debugger_frame.cpp b/rpcs3/rpcs3qt/debugger_frame.cpp index fdc8880368..014480f5b4 100644 --- a/rpcs3/rpcs3qt/debugger_frame.cpp +++ b/rpcs3/rpcs3qt/debugger_frame.cpp @@ -190,8 +190,7 @@ debugger_frame::debugger_frame(std::shared_ptr gui_settings, QWidg m_choice_units->clearFocus(); }); - connect(m_choice_units, QOverload::of(&QComboBox::activated), this, &debugger_frame::UpdateUI); - connect(m_choice_units, QOverload::of(&QComboBox::currentIndexChanged), this, [&](){ m_is_spu_disasm_mode = false; OnSelectUnit(); }); + connect(m_choice_units, QOverload::of(&QComboBox::activated), this, [&](){ m_is_spu_disasm_mode = false; OnSelectUnit(); }); connect(this, &QDockWidget::visibilityChanged, this, &debugger_frame::EnableUpdateTimer); connect(m_debugger_list, &debugger_list::BreakpointRequested, m_breakpoint_list, &breakpoint_list::HandleBreakpointRequest); @@ -201,7 +200,9 @@ debugger_frame::debugger_frame(std::shared_ptr gui_settings, QWidg connect(m_call_stack_list, &call_stack_list::RequestShowAddress, m_debugger_list, &debugger_list::ShowAddress); m_debugger_list->RefreshView(); - UpdateUnitList(); + + m_choice_units->clear(); + m_choice_units->addItem(NoThreadString); } void debugger_frame::SaveSettings() const @@ -914,7 +915,7 @@ void debugger_frame::UpdateUI() ShowPC(); } - if (m_ui_update_ctr % 20 == 0) + if (m_ui_update_ctr % 20 == 0 && !m_thread_list_pending_update) { // Update threads list at 5hz (low priority) UpdateUnitList(); @@ -924,7 +925,12 @@ void debugger_frame::UpdateUI() { if (m_last_pc != umax || !m_last_query_state.empty()) { - UpdateUnitList(); + if (m_ui_update_ctr % 20 && !m_thread_list_pending_update) + { + // Update threads list (thread exited) + UpdateUnitList(); + } + ShowPC(); m_last_query_state.clear(); m_last_pc = -1; @@ -985,57 +991,79 @@ void debugger_frame::UpdateUnitList() const u64 threads_deleted = cpu_thread::g_threads_deleted; const system_state emu_state = Emu.GetStatus(); - if (emulation_id != m_emulation_id || threads_created != m_threads_created || threads_deleted != m_threads_deleted || emu_state != m_emu_state) - { - m_emulation_id = emulation_id; - m_threads_created = threads_created; - m_threads_deleted = threads_deleted; - m_emu_state = emu_state; - } - else + std::unique_lock lock{id_manager::g_mutex, std::defer_lock}; + + if (emulation_id == m_emulation_id && threads_created == m_threads_created && threads_deleted == m_threads_deleted && emu_state == m_emu_state) { // Nothing to do + m_thread_list_pending_update = false; return; } QVariant old_cpu = m_choice_units->currentData(); + const cpu_thread* old_cpu_ptr = old_cpu.canConvert() ? old_cpu.value()() : nullptr; - bool reselected = false; + if (!lock.try_lock()) + { + m_thread_list_pending_update = true; + QTimer::singleShot(5, [this]() { UpdateUnitList(); }); + return; + } + + m_emulation_id = emulation_id; + m_threads_created = threads_created; + m_threads_deleted = threads_deleted; + m_emu_state = emu_state; + + std::vector> cpu_list; + usz reselected_index = umax; const auto on_select = [&](u32 id, cpu_thread& cpu) { - const QVariant var_cpu = QVariant::fromValue(make_check_cpu(std::addressof(cpu), true)); + QVariant var_cpu = QVariant::fromValue(make_check_cpu(std::addressof(cpu), true)); // Space at the end is to pad a gap on the right - m_choice_units->addItem(qstr((id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()) + ' '), var_cpu); + cpu_list.emplace_back(qstr((id >> 24 == 0x55 ? "RSX[0x55555555]" : cpu.get_name()) + ' '), std::move(var_cpu)); - if (!reselected && old_cpu.canConvert() && old_cpu.value()() == std::addressof(cpu)) + if (old_cpu_ptr == std::addressof(cpu)) { - m_choice_units->setCurrentIndex(m_choice_units->count() - 1); - reselected = true; + reselected_index = cpu_list.size() - 1; } }; + if (emu_state != system_state::stopped) + { + idm::select>(on_select, idm::unlocked); + idm::select>(on_select, idm::unlocked); + } + + if (const auto render = g_fxo->try_get(); emu_state != system_state::stopped && render && render->ctrl) + { + on_select(render->id, *render); + } + + lock.unlock(); + m_thread_list_pending_update = false; + { const QSignalBlocker blocker(m_choice_units); m_choice_units->clear(); m_choice_units->addItem(NoThreadString); - if (emu_state != system_state::stopped) + for (auto&& [thread_name, var_cpu] : cpu_list) { - idm::select>(on_select); - idm::select>(on_select); + m_choice_units->addItem(std::move(thread_name), std::move(var_cpu)); } - if (const auto render = g_fxo->try_get(); emu_state != system_state::stopped && render && render->ctrl) + if (reselected_index != umax) { - on_select(render->id, *render); + m_choice_units->setCurrentIndex(reselected_index); } } // Close dialogs which are tied to the specific thread selected - if (!reselected) + if (reselected_index == umax) { if (m_reg_editor) m_reg_editor->close(); if (m_inst_editor) m_inst_editor->close(); diff --git a/rpcs3/rpcs3qt/debugger_frame.h b/rpcs3/rpcs3qt/debugger_frame.h index c39a8f05ad..09787ba53c 100644 --- a/rpcs3/rpcs3qt/debugger_frame.h +++ b/rpcs3/rpcs3qt/debugger_frame.h @@ -54,6 +54,7 @@ class debugger_frame : public custom_dock_widget QPushButton* m_btn_step; QPushButton* m_btn_step_over; QPushButton* m_btn_run; + QComboBox* m_choice_units; QTimer* m_update; QSplitter* m_splitter; @@ -69,6 +70,7 @@ class debugger_frame : public custom_dock_widget u32 m_last_step_over_breakpoint = -1; u64 m_ui_update_ctr = 0; u64 m_ui_fast_update_permission_deadline = 0; + bool m_thread_list_pending_update = false; std::shared_ptr m_disasm; // Only shared to allow base/derived functionality std::shared_ptr m_cpu; diff --git a/rpcs3/rpcs3qt/debugger_list.cpp b/rpcs3/rpcs3qt/debugger_list.cpp index 8d16409470..9123df3907 100644 --- a/rpcs3/rpcs3qt/debugger_list.cpp +++ b/rpcs3/rpcs3qt/debugger_list.cpp @@ -46,7 +46,7 @@ debugger_list::debugger_list(QWidget* parent, std::shared_ptr gui_ u32 pc = m_start_addr; - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; for (; cpu && cpu->get_class() == thread_class::rsx && row; row--) { @@ -71,7 +71,7 @@ void debugger_list::UpdateCPUData(std::shared_ptr disasm) u32 debugger_list::GetStartAddress(u32 address) { - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; const u32 steps = m_item_count / 3; const u32 inst_count_jump_on_step = std::min(steps, 4); @@ -134,14 +134,14 @@ u32 debugger_list::GetStartAddress(u32 address) bool debugger_list::IsSpu() const { - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; return (cpu && cpu->get_class() == thread_class::spu) || (m_disasm && !cpu); } void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct) { - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; const decltype(spu_thread::local_breakpoints)* spu_bps_list{}; @@ -299,7 +299,7 @@ void debugger_list::EnableThreadFollowing(bool enable) void debugger_list::scroll(s32 steps) { - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; for (; cpu && cpu->get_class() == thread_class::rsx && steps > 0; steps--) { @@ -324,7 +324,7 @@ void debugger_list::scroll(s32 steps) void debugger_list::keyPressEvent(QKeyEvent* event) { - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; // Always accept event (so it would not bubble upwards, debugger_frame already sees it) struct accept_event_t @@ -436,7 +436,7 @@ void debugger_list::mouseDoubleClickEvent(QMouseEvent* event) u32 pc = m_start_addr; - const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr; + const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr; for (; cpu && cpu->get_class() == thread_class::rsx && i; i--) {