|
@@ -6,173 +6,11 @@
|
|
|
#include <SharedGraphics/GraphicsBitmap.h>
|
|
|
#include <SharedGraphics/Painter.h>
|
|
|
#include <LibGUI/GScrollBar.h>
|
|
|
-#include <LibGUI/GTableModel.h>
|
|
|
+#include "ProcessTableModel.h"
|
|
|
#include "ProcessView.h"
|
|
|
|
|
|
static HashMap<unsigned, String>* s_usernames;
|
|
|
|
|
|
-class ProcessTableModel final : public GTableModel {
|
|
|
-public:
|
|
|
- ProcessTableModel()
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
- virtual ~ProcessTableModel() override { }
|
|
|
-
|
|
|
- virtual int row_count() const override { return m_processes.size(); }
|
|
|
- virtual int column_count() const override { return 4; }
|
|
|
-
|
|
|
- virtual String column_name(int column) const override
|
|
|
- {
|
|
|
- switch (column) {
|
|
|
- case 0: return "PID";
|
|
|
- case 1: return "State";
|
|
|
- case 2: return "CPU";
|
|
|
- case 3: return "Name";
|
|
|
- default: ASSERT_NOT_REACHED();
|
|
|
- }
|
|
|
- }
|
|
|
- virtual int column_width(int column) const override
|
|
|
- {
|
|
|
- switch (column) {
|
|
|
- case 0: return 30;
|
|
|
- case 1: return 80;
|
|
|
- case 2: return 30;
|
|
|
- case 3: return 200;
|
|
|
- default: ASSERT_NOT_REACHED();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- virtual GModelIndex selected_index() const override { return { m_selected_row, 0 }; }
|
|
|
- virtual void set_selected_index(GModelIndex index) override
|
|
|
- {
|
|
|
- if (index.row() >= 0 && index.row() < m_pids.size())
|
|
|
- m_selected_row = index.row();
|
|
|
- }
|
|
|
-
|
|
|
- virtual String data(int row, int column) const override
|
|
|
- {
|
|
|
- if (row < 0 || row >= row_count())
|
|
|
- return { };
|
|
|
- if (column < 0 || column >= column_count())
|
|
|
- return { };
|
|
|
- auto it = m_processes.find(m_pids[row]);
|
|
|
- auto& process = *(*it).value;
|
|
|
- switch (column) {
|
|
|
- case 0: return String::format("%d", process.current_state.pid);
|
|
|
- case 1: return process.current_state.state;
|
|
|
- case 2: return String::format("%d", (int)process.current_state.cpu_percent);
|
|
|
- case 3: return process.current_state.name;
|
|
|
- }
|
|
|
- ASSERT_NOT_REACHED();
|
|
|
- }
|
|
|
-
|
|
|
- virtual void update() override
|
|
|
- {
|
|
|
- FILE* fp = fopen("/proc/all", "r");
|
|
|
- if (!fp) {
|
|
|
- perror("failed to open /proc/all");
|
|
|
- exit(1);
|
|
|
- }
|
|
|
-
|
|
|
- unsigned last_sum_nsched = 0;
|
|
|
- for (auto& it : m_processes)
|
|
|
- last_sum_nsched += it.value->current_state.nsched;
|
|
|
-
|
|
|
- HashTable<pid_t> live_pids;
|
|
|
- unsigned sum_nsched = 0;
|
|
|
- for (;;) {
|
|
|
- char buf[BUFSIZ];
|
|
|
- char* ptr = fgets(buf, sizeof(buf), fp);
|
|
|
- if (!ptr)
|
|
|
- break;
|
|
|
- auto parts = String(buf, Chomp).split(',');
|
|
|
- if (parts.size() < 17)
|
|
|
- break;
|
|
|
- bool ok;
|
|
|
- pid_t pid = parts[0].to_uint(ok);
|
|
|
- ASSERT(ok);
|
|
|
- unsigned nsched = parts[1].to_uint(ok);
|
|
|
- ASSERT(ok);
|
|
|
- ProcessState state;
|
|
|
- state.pid = pid;
|
|
|
- state.nsched = nsched;
|
|
|
- unsigned uid = parts[5].to_uint(ok);
|
|
|
- ASSERT(ok);
|
|
|
- //state.user = s_usernames->get(uid);
|
|
|
- state.user = String::format("%u", uid);
|
|
|
- state.priority = parts[16];
|
|
|
- state.state = parts[7];
|
|
|
- state.name = parts[11];
|
|
|
- state.linear = parts[12].to_uint(ok);
|
|
|
- ASSERT(ok);
|
|
|
- state.committed = parts[13].to_uint(ok);
|
|
|
- ASSERT(ok);
|
|
|
-
|
|
|
- {
|
|
|
- auto it = m_processes.find(pid);
|
|
|
- if (it == m_processes.end())
|
|
|
- m_processes.set(pid, make<Process>());
|
|
|
- }
|
|
|
- auto it = m_processes.find(pid);
|
|
|
- ASSERT(it != m_processes.end());
|
|
|
- (*it).value->previous_state = (*it).value->current_state;
|
|
|
- (*it).value->current_state = state;
|
|
|
-
|
|
|
- live_pids.set(pid);
|
|
|
-
|
|
|
- sum_nsched += nsched;
|
|
|
- }
|
|
|
- int rc = fclose(fp);
|
|
|
- ASSERT(rc == 0);
|
|
|
-
|
|
|
- m_pids.clear();
|
|
|
- Vector<pid_t> pids_to_remove;
|
|
|
- for (auto& it : m_processes) {
|
|
|
- if (!live_pids.contains(it.key)) {
|
|
|
- pids_to_remove.append(it.key);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- auto& process = *it.value;
|
|
|
- dword nsched_diff = process.current_state.nsched - process.previous_state.nsched;
|
|
|
- process.current_state.cpu_percent = ((float)nsched_diff * 100) / (float)(sum_nsched - last_sum_nsched);
|
|
|
- m_pids.append(it.key);
|
|
|
- }
|
|
|
- for (auto pid : pids_to_remove)
|
|
|
- m_processes.remove(pid);
|
|
|
- }
|
|
|
-
|
|
|
- pid_t selected_pid() const
|
|
|
- {
|
|
|
- if (m_selected_row == -1)
|
|
|
- return -1;
|
|
|
- return m_pids[m_selected_row];
|
|
|
- }
|
|
|
-
|
|
|
-private:
|
|
|
- struct ProcessState {
|
|
|
- pid_t pid;
|
|
|
- unsigned nsched;
|
|
|
- String name;
|
|
|
- String state;
|
|
|
- String user;
|
|
|
- String priority;
|
|
|
- unsigned linear;
|
|
|
- unsigned committed;
|
|
|
- float cpu_percent;
|
|
|
- };
|
|
|
-
|
|
|
- struct Process {
|
|
|
- ProcessState current_state;
|
|
|
- ProcessState previous_state;
|
|
|
- };
|
|
|
-
|
|
|
- HashMap<pid_t, OwnPtr<Process>> m_processes;
|
|
|
- Vector<pid_t> m_pids;
|
|
|
- int m_selected_row { -1 };
|
|
|
-};
|
|
|
-
|
|
|
ProcessView::ProcessView(GWidget* parent)
|
|
|
: GWidget(parent)
|
|
|
{
|