Serenity Operating System
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}