Serenity Operating System
at master 138 lines 3.7 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include "ThreadStackWidget.h" 9#include <LibCore/Timer.h> 10#include <LibGUI/BoxLayout.h> 11#include <LibGUI/Model.h> 12#include <LibGUI/Widget.h> 13#include <LibSymbolication/Symbolication.h> 14#include <LibThreading/BackgroundAction.h> 15 16REGISTER_WIDGET(SystemMonitor, ThreadStackWidget) 17 18namespace SystemMonitor { 19 20class ThreadStackModel final : public GUI::Model { 21 22 enum Column { 23 Address, 24 Object, 25 Symbol 26 }; 27 28public: 29 int column_count(GUI::ModelIndex const&) const override { return 3; }; 30 int row_count(GUI::ModelIndex const&) const override { return m_symbols.size(); }; 31 bool is_column_sortable(int) const override { return false; } 32 33 DeprecatedString column_name(int column) const override 34 { 35 switch (column) { 36 case Column::Address: 37 return "Address"; 38 case Column::Object: 39 return "Object"; 40 case Column::Symbol: 41 return "Symbol"; 42 default: 43 VERIFY_NOT_REACHED(); 44 } 45 } 46 47 GUI::Variant data(GUI::ModelIndex const& model_index, GUI::ModelRole) const override 48 { 49 auto& symbol = m_symbols[model_index.row()]; 50 switch (model_index.column()) { 51 case Column::Address: 52 return DeprecatedString::formatted("{:p}", symbol.address); 53 case Column::Object: 54 return symbol.object; 55 case Column::Symbol: 56 return symbol.name; 57 default: 58 VERIFY_NOT_REACHED(); 59 } 60 }; 61 62 void set_symbols(Vector<Symbolication::Symbol> const& symbols) 63 { 64 if (m_symbols == symbols) 65 return; 66 m_symbols = symbols; 67 invalidate(); 68 } 69 70private: 71 Vector<Symbolication::Symbol> m_symbols; 72}; 73 74ThreadStackWidget::ThreadStackWidget() 75{ 76 set_layout<GUI::VerticalBoxLayout>(4); 77 m_stack_table = add<GUI::TableView>(); 78 m_stack_table->set_model(adopt_ref(*new ThreadStackModel())); 79} 80 81void ThreadStackWidget::show_event(GUI::ShowEvent&) 82{ 83 refresh(); 84 if (!m_timer) { 85 m_timer = add<Core::Timer>(1000, [this] { refresh(); }); 86 m_timer->start(); 87 } 88} 89 90void ThreadStackWidget::hide_event(GUI::HideEvent&) 91{ 92 m_timer = nullptr; 93} 94 95void ThreadStackWidget::set_ids(pid_t pid, pid_t tid) 96{ 97 if (m_pid == pid && m_tid == tid) 98 return; 99 m_pid = pid; 100 m_tid = tid; 101} 102 103class CompletionEvent : public Core::CustomEvent { 104public: 105 explicit CompletionEvent(Vector<Symbolication::Symbol> symbols) 106 : Core::CustomEvent(0) 107 , m_symbols(move(symbols)) 108 { 109 } 110 111 Vector<Symbolication::Symbol> const& symbols() const { return m_symbols; } 112 113private: 114 Vector<Symbolication::Symbol> m_symbols; 115}; 116 117void ThreadStackWidget::refresh() 118{ 119 (void)Threading::BackgroundAction<Vector<Symbolication::Symbol>>::construct( 120 [pid = m_pid, tid = m_tid](auto&) { 121 return Symbolication::symbolicate_thread(pid, tid, Symbolication::IncludeSourcePosition::No); 122 }, 123 124 [weak_this = make_weak_ptr()](auto result) -> ErrorOr<void> { 125 if (!weak_this) 126 return {}; 127 Core::EventLoop::current().post_event(const_cast<Core::Object&>(*weak_this), make<CompletionEvent>(move(result))); 128 return {}; 129 }); 130} 131 132void ThreadStackWidget::custom_event(Core::CustomEvent& event) 133{ 134 auto& completion_event = verify_cast<CompletionEvent>(event); 135 verify_cast<ThreadStackModel>(m_stack_table->model())->set_symbols(completion_event.symbols()); 136} 137 138}