summaryrefslogtreecommitdiff
path: root/Userland/Applications/SystemMonitor/ThreadStackWidget.cpp
blob: 4f14651bc012887fd5edebae6ea3cfe037bd1ba8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
 * Copyright (c) 2022, the SerenityOS developers.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include "ThreadStackWidget.h"
#include <LibCore/Timer.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Model.h>
#include <LibGUI/Widget.h>
#include <LibSymbolication/Symbolication.h>
#include <LibThreading/BackgroundAction.h>

REGISTER_WIDGET(SystemMonitor, ThreadStackWidget)

namespace SystemMonitor {

class ThreadStackModel final : public GUI::Model {

    enum Column {
        Address,
        Object,
        Symbol
    };

public:
    int column_count(GUI::ModelIndex const&) const override { return 3; };
    int row_count(GUI::ModelIndex const&) const override { return m_symbols.size(); };
    bool is_column_sortable(int) const override { return false; }

    DeprecatedString column_name(int column) const override
    {
        switch (column) {
        case Column::Address:
            return "Address";
        case Column::Object:
            return "Object";
        case Column::Symbol:
            return "Symbol";
        default:
            VERIFY_NOT_REACHED();
        }
    }

    GUI::Variant data(GUI::ModelIndex const& model_index, GUI::ModelRole) const override
    {
        auto& symbol = m_symbols[model_index.row()];
        switch (model_index.column()) {
        case Column::Address:
            return DeprecatedString::formatted("{:p}", symbol.address);
        case Column::Object:
            return symbol.object;
        case Column::Symbol:
            return symbol.name;
        default:
            VERIFY_NOT_REACHED();
        }
    };

    void set_symbols(Vector<Symbolication::Symbol> const& symbols)
    {
        if (m_symbols == symbols)
            return;
        m_symbols = symbols;
        invalidate();
    }

private:
    Vector<Symbolication::Symbol> m_symbols;
};

ThreadStackWidget::ThreadStackWidget()
{
    set_layout<GUI::VerticalBoxLayout>();
    layout()->set_margins(4);
    m_stack_table = add<GUI::TableView>();
    m_stack_table->set_model(adopt_ref(*new ThreadStackModel()));
}

void ThreadStackWidget::show_event(GUI::ShowEvent&)
{
    refresh();
    if (!m_timer) {
        m_timer = add<Core::Timer>(1000, [this] { refresh(); });
        m_timer->start();
    }
}

void ThreadStackWidget::hide_event(GUI::HideEvent&)
{
    m_timer = nullptr;
}

void ThreadStackWidget::set_ids(pid_t pid, pid_t tid)
{
    if (m_pid == pid && m_tid == tid)
        return;
    m_pid = pid;
    m_tid = tid;
}

class CompletionEvent : public Core::CustomEvent {
public:
    explicit CompletionEvent(Vector<Symbolication::Symbol> symbols)
        : Core::CustomEvent(0)
        , m_symbols(move(symbols))
    {
    }

    Vector<Symbolication::Symbol> const& symbols() const { return m_symbols; }

private:
    Vector<Symbolication::Symbol> m_symbols;
};

void ThreadStackWidget::refresh()
{
    (void)Threading::BackgroundAction<Vector<Symbolication::Symbol>>::construct(
        [pid = m_pid, tid = m_tid](auto&) {
            return Symbolication::symbolicate_thread(pid, tid, Symbolication::IncludeSourcePosition::No);
        },

        [weak_this = make_weak_ptr()](auto result) -> ErrorOr<void> {
            if (!weak_this)
                return {};
            Core::EventLoop::current().post_event(const_cast<Core::Object&>(*weak_this), make<CompletionEvent>(move(result)));
            return {};
        });
}

void ThreadStackWidget::custom_event(Core::CustomEvent& event)
{
    auto& completion_event = verify_cast<CompletionEvent>(event);
    verify_cast<ThreadStackModel>(m_stack_table->model())->set_symbols(completion_event.symbols());
}

}