From 272317bce27b9def41d0b5f53931bf90abb0bcba Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 24 Oct 2019 20:21:43 +0200 Subject: [PATCH] HackStudio: Add a widget showing the state of console's running process We now have a little widget that sits above the terminal view in the build/application console. When a child process is running, we show its PID, name, scheduling counter, and amount of resident memory in a live little overview. This is not working right just yet, since we don't know how to get to the actually active PID on the TTY. Or, well, we find the active PID by looking at the PGID of our fork()ed child. This manages to find children spawned by Shell, but not children spawned by make, for instance. I need to figure out how to find those. --- DevTools/HackStudio/Makefile | 1 + DevTools/HackStudio/ProcessStateWidget.cpp | 71 ++++++++++++++++++++++ DevTools/HackStudio/ProcessStateWidget.h | 28 +++++++++ DevTools/HackStudio/TerminalWrapper.cpp | 7 +++ DevTools/HackStudio/TerminalWrapper.h | 2 + 5 files changed, 109 insertions(+) create mode 100644 DevTools/HackStudio/ProcessStateWidget.cpp create mode 100644 DevTools/HackStudio/ProcessStateWidget.h diff --git a/DevTools/HackStudio/Makefile b/DevTools/HackStudio/Makefile index c96a770342..728552f7c3 100644 --- a/DevTools/HackStudio/Makefile +++ b/DevTools/HackStudio/Makefile @@ -5,6 +5,7 @@ OBJS = \ TextDocument.o \ TerminalWrapper.o \ FindInFilesWidget.o \ + ProcessStateWidget.o \ main.o APP = HackStudio diff --git a/DevTools/HackStudio/ProcessStateWidget.cpp b/DevTools/HackStudio/ProcessStateWidget.cpp new file mode 100644 index 0000000000..98a0ab4bbb --- /dev/null +++ b/DevTools/HackStudio/ProcessStateWidget.cpp @@ -0,0 +1,71 @@ +#include "ProcessStateWidget.h" +#include +#include +#include +#include + +ProcessStateWidget::ProcessStateWidget(GWidget* parent) + : GWidget(parent) +{ + set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + set_preferred_size(0, 20); + + set_layout(make(Orientation::Horizontal)); + + auto pid_label_label = GLabel::construct("Process:", this); + pid_label_label->set_font(Font::default_bold_font()); + m_pid_label = GLabel::construct("", this); + + auto state_label_label = GLabel::construct("State:", this); + state_label_label->set_font(Font::default_bold_font()); + m_state_label = GLabel::construct("", this); + + // FIXME: This should show CPU% instead. + auto cpu_label_label = GLabel::construct("Times scheduled:", this); + cpu_label_label->set_font(Font::default_bold_font()); + m_cpu_label = GLabel::construct("", this); + + auto memory_label_label = GLabel::construct("Memory (resident):", this); + memory_label_label->set_font(Font::default_bold_font()); + m_memory_label = GLabel::construct("", this); + + m_timer = CTimer::construct(500, [this] { + refresh(); + }); +} + +ProcessStateWidget::~ProcessStateWidget() +{ +} + +void ProcessStateWidget::refresh() +{ + if (m_pid == -1) { + m_pid_label->set_text("(none)"); + m_state_label->set_text("n/a"); + m_cpu_label->set_text("n/a"); + m_memory_label->set_text("n/a"); + return; + } + + auto processes = CProcessStatisticsReader::get_all(); + auto child_process_data = processes.get(m_pid); + + if (!child_process_data.has_value()) + return; + + auto active_process_data = processes.get(child_process_data.value().pgid); + + auto& data = active_process_data.value(); + + m_pid_label->set_text(String::format("%s(%d)", data.name.characters(), m_pid)); + m_state_label->set_text(data.state); + m_cpu_label->set_text(String::format("%d", data.times_scheduled)); + m_memory_label->set_text(String::format("%d", data.amount_resident)); +} + +void ProcessStateWidget::set_pid(pid_t pid) +{ + m_pid = pid; + refresh(); +} diff --git a/DevTools/HackStudio/ProcessStateWidget.h b/DevTools/HackStudio/ProcessStateWidget.h new file mode 100644 index 0000000000..5f9c35c0c0 --- /dev/null +++ b/DevTools/HackStudio/ProcessStateWidget.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +class CTimer; +class GLabel; + +class ProcessStateWidget final : public GWidget { + C_OBJECT(ProcessStateWidget) +public: + virtual ~ProcessStateWidget() override; + + void set_pid(pid_t); + +private: + explicit ProcessStateWidget(GWidget* parent); + + void refresh(); + + RefPtr m_pid_label; + RefPtr m_state_label; + RefPtr m_cpu_label; + RefPtr m_memory_label; + + RefPtr m_timer; + + pid_t m_pid { -1 }; +}; diff --git a/DevTools/HackStudio/TerminalWrapper.cpp b/DevTools/HackStudio/TerminalWrapper.cpp index 26c80bfa46..6ee696eed9 100644 --- a/DevTools/HackStudio/TerminalWrapper.cpp +++ b/DevTools/HackStudio/TerminalWrapper.cpp @@ -1,4 +1,5 @@ #include "TerminalWrapper.h" +#include "ProcessStateWidget.h" #include #include #include @@ -44,6 +45,7 @@ void TerminalWrapper::run_command(const String& command) } else if (WIFSIGNALED(wstatus)) { m_terminal_widget->inject_string(String::format("\033[34;1m(Command signaled with %s!)\033[0m\n", strsignal(WTERMSIG(wstatus)))); } + m_process_state_widget->set_pid(-1); m_pid = -1; }; @@ -106,6 +108,9 @@ void TerminalWrapper::run_command(const String& command) } ASSERT_NOT_REACHED(); } + + // Parent process, cont'd. + m_process_state_widget->set_pid(m_pid); } TerminalWrapper::TerminalWrapper(GWidget* parent) @@ -113,6 +118,8 @@ TerminalWrapper::TerminalWrapper(GWidget* parent) { set_layout(make(Orientation::Vertical)); + m_process_state_widget = ProcessStateWidget::construct(this); + RefPtr config = CConfigFile::get_for_app("Terminal"); m_terminal_widget = TerminalWidget::construct(-1, false, config); add_child(*m_terminal_widget); diff --git a/DevTools/HackStudio/TerminalWrapper.h b/DevTools/HackStudio/TerminalWrapper.h index 90ca7c44e4..5da7766199 100644 --- a/DevTools/HackStudio/TerminalWrapper.h +++ b/DevTools/HackStudio/TerminalWrapper.h @@ -2,6 +2,7 @@ #include +class ProcessStateWidget; class TerminalWidget; class TerminalWrapper final : public GWidget { @@ -14,6 +15,7 @@ public: private: explicit TerminalWrapper(GWidget* parent); + RefPtr m_process_state_widget; RefPtr m_terminal_widget; pid_t m_pid { -1 }; };