diff --git a/src/Managers/IProcess.vala b/src/Managers/IProcess.vala new file mode 100644 index 00000000..7ccf9940 --- /dev/null +++ b/src/Managers/IProcess.vala @@ -0,0 +1,68 @@ +public interface Monitor.IProcess : Object { + + public abstract signal void fd_permission_error (string error); + + /** Whether or not the PID leads to something */ + public abstract bool exists { get; public set; } + + // Full command from cmdline file + public abstract string command { get; protected set; } + + // If process is an installed app, this will contain its name, + // otherwise it is just a trimmed command + public abstract string application_name { get; set; } + + // User id + public abstract int uid { get; protected set; } + + public abstract string username { get; protected set; } + + public abstract Icon icon { get; set; } + + // Contains info about io + public abstract ProcessIO io { get; public set; } + + // Contains status info + public abstract ProcessStatus stat { get; public set; } + + public abstract ProcessStatusMemory statm { get; public set; } + + public abstract Gee.HashSet open_files_paths { get; public set; } + + public abstract Gee.HashSet children { get; public set; } + + public abstract double cpu_percentage { get; protected set; } + + protected abstract uint64 cpu_last_used { get; protected set; } + + // Memory usage of the process, measured in KiB. + public abstract uint64 mem_usage { get; protected set; } + public abstract double mem_percentage { get; protected set; } + + public abstract uint64 last_total { get; protected set; } + + private abstract const int HISTORY_BUFFER_SIZE = 30; + public abstract Gee.ArrayList cpu_percentage_history { get; protected set; } + public abstract Gee.ArrayList mem_percentage_history { get; protected set; } + + protected abstract int get_uid (); + + public abstract bool update (uint64 cpu_total, uint64 cpu_last_total); + + public abstract bool kill (); + public abstract bool end (); + + public abstract bool get_children_pids (); + + public abstract bool parse_io (); + + public abstract bool parse_stat (); + + public abstract bool parse_statm (); + + public abstract bool get_open_files (); + + public abstract bool read_cmdline (); + + public abstract void get_usage (uint64 cpu_total, uint64 cpu_last_total); +} diff --git a/src/Managers/Process.vala b/src/Managers/Process.vala index bd6342d0..0ca228e3 100644 --- a/src/Managers/Process.vala +++ b/src/Managers/Process.vala @@ -1,24 +1,22 @@ -public class Monitor.Process : GLib.Object { +public class Monitor.Process : IProcess, GLib.Object { // The size of each RSS page, in bytes // private static long PAGESIZE = Posix.sysconf (Posix._SC_PAGESIZE); - public signal void fd_permission_error (string error); - // Whether or not the PID leads to something - public bool exists { get; protected set; } + public bool exists { get; private set; } // Full command from cmdline file - public string command { get; protected set; } + public string command { get; private set; } // If process is an installed app, this will contain its name, // otherwise it is just a trimmed command - public string application_name; + public string application_name { get; set; } // User id - public int uid; + public int uid { get; private set; } - public string username = Utils.NO_DATA; + public string username { get; private set; default = Utils.NO_DATA; } Icon _icon; public Icon icon { @@ -35,35 +33,35 @@ public class Monitor.Process : GLib.Object { } // Contains info about io - public ProcessIO io; + public ProcessIO io { get; private set; } // Contains status info - public ProcessStatus stat; + public ProcessStatus stat { get; private set; } - public ProcessStatusMemory statm; + public ProcessStatusMemory statm { get; private set; } - public Gee.HashSet open_files_paths; + public Gee.HashSet open_files_paths { get; private set; } - public Gee.HashSet children = new Gee.HashSet (); + public Gee.HashSet children { get; private set; default = new Gee.HashSet (); } /** * CPU usage of this process from the last time that it was updated, measured in percent * * Will be 0 on first update. */ - public double cpu_percentage { get; protected set; } + public double cpu_percentage { get; private set; } - protected uint64 cpu_last_used; + private uint64 cpu_last_used { get; private set; } // Memory usage of the process, measured in KiB. - public uint64 mem_usage { get; protected set; } - public double mem_percentage { get; protected set; } + public uint64 mem_usage { get; private set; } + public double mem_percentage { get; private set; } - protected uint64 last_total; + private uint64 last_total { get; private set; } - protected const int HISTORY_BUFFER_SIZE = 30; - public Gee.ArrayList cpu_percentage_history = new Gee.ArrayList (); - public Gee.ArrayList mem_percentage_history = new Gee.ArrayList (); + private const int HISTORY_BUFFER_SIZE = 30; + public Gee.ArrayList cpu_percentage_history { get; private set; default = new Gee.ArrayList (); } + public Gee.ArrayList mem_percentage_history { get; private set; default = new Gee.ArrayList (); } @@ -95,14 +93,7 @@ public class Monitor.Process : GLib.Object { get_usage (0, 1); } - protected int get_uid () { - if (ProcessUtils.is_flatpak_env ()) { - var process_provider = ProcessProvider.get_default (); - string ? status = process_provider.pids_status.get (this.stat.pid); - var status_line = status.split ("\n"); - return int.parse (status_line[8].split ("\t")[1]); - - } + private int get_uid () { GTop.ProcUid proc_uid; GTop.get_proc_uid (out proc_uid, stat.pid); return proc_uid.uid; @@ -139,7 +130,7 @@ public class Monitor.Process : GLib.Object { return false; } - protected bool get_children_pids () { + private bool get_children_pids () { string ? children_content = ProcessUtils.read_file ("/proc/%d/task/%d/children".printf (stat.pid, stat.pid)); if (children_content == "" || children_content == null) { return false; @@ -152,7 +143,7 @@ public class Monitor.Process : GLib.Object { return true; } - protected bool parse_io () { + private bool parse_io () { var io_file = File.new_for_path ("/proc/%d/io".printf (stat.pid)); if (!io_file.query_exists ()) { @@ -205,7 +196,7 @@ public class Monitor.Process : GLib.Object { } // Reads the /proc/%pid%/stat file and updates the process with the information therein. - protected bool parse_stat () { + private bool parse_stat () { string ? stat_contents; if (ProcessUtils.is_flatpak_env ()) { var process_provider = ProcessProvider.get_default (); @@ -248,14 +239,8 @@ public class Monitor.Process : GLib.Object { return true; } - protected bool parse_statm () { - string ? statm_contents; - if (ProcessUtils.is_flatpak_env ()) { - var process_provider = ProcessProvider.get_default (); - statm_contents = process_provider.pids_stat.get (this.stat.pid); - } else { - statm_contents = ProcessUtils.read_file ("/proc/%d/statm".printf (stat.pid)); - } + private bool parse_statm () { + string ? statm_contents = ProcessUtils.read_file ("/proc/%d/statm".printf (stat.pid)); if (statm_contents == null) return false; @@ -271,7 +256,7 @@ public class Monitor.Process : GLib.Object { return true; } - protected bool get_open_files () { + private bool get_open_files () { // try { // string directory = "/proc/%d/fd".printf (stat.pid); // Dir dir = Dir.open (directory, 0); @@ -298,14 +283,8 @@ public class Monitor.Process : GLib.Object { /** * Reads the /proc/%pid%/cmdline file and updates from the information contained therein. */ - protected bool read_cmdline () { - string ? cmdline; - if (ProcessUtils.is_flatpak_env ()) { - var process_provider = ProcessProvider.get_default (); - cmdline = process_provider.pids_cmdline.get (this.stat.pid); - } else { - cmdline = ProcessUtils.read_file ("/proc/%d/cmdline".printf (stat.pid)); - } + private bool read_cmdline () { + string ? cmdline = ProcessUtils.read_file ("/proc/%d/cmdline".printf (stat.pid)); if (cmdline == null) { return false; @@ -323,7 +302,7 @@ public class Monitor.Process : GLib.Object { return true; } - protected void get_usage (uint64 cpu_total, uint64 cpu_last_total) { + private void get_usage (uint64 cpu_total, uint64 cpu_last_total) { // Get CPU usage by process GTop.ProcTime proc_time; GTop.get_proc_time (out proc_time, stat.pid); diff --git a/src/Managers/ProcessManager.vala b/src/Managers/ProcessManager.vala index cbf6ce34..3a7014c1 100644 --- a/src/Managers/ProcessManager.vala +++ b/src/Managers/ProcessManager.vala @@ -13,17 +13,17 @@ namespace Monitor { uint64[] cpu_last_useds = new uint64[32]; uint64[] cpu_last_totals = new uint64[32]; - private Gee.TreeMap process_list; + private Gee.TreeMap process_list; private Gee.HashSet kernel_process_blacklist; private Gee.HashMap apps_info_list; - public signal void process_added (Process process); + public signal void process_added (IProcess process); public signal void process_removed (int pid); public signal void updated (); // Construct a new ProcessManager public ProcessManager () { - process_list = new Gee.TreeMap (); + process_list = new Gee.TreeMap (); kernel_process_blacklist = new Gee.HashSet (); apps_info_list = new Gee.HashMap (); @@ -53,7 +53,7 @@ namespace Monitor { /** * Gets a process by its pid, making sure that it's updated. */ - public Process ? get_process (int pid) { + public IProcess ? get_process (int pid) { // if the process is in the kernel blacklist, we don't want to deal with it. if (kernel_process_blacklist.contains (pid)) { return null; @@ -90,7 +90,7 @@ namespace Monitor { /** * Gets a read only map of the processes currently cached */ - public Gee.Map get_process_list () { + public Gee.Map get_process_list () { return process_list.read_only_view; } @@ -150,7 +150,7 @@ namespace Monitor { } /** Sets name and icon for a process that is a Flatpak app and its children. */ - private void set_flatpak_name_icon (Process process, GLib.Icon icon, string name) { + private void set_flatpak_name_icon (IProcess process, GLib.Icon icon, string name) { process.application_name = name; process.icon = icon; foreach (int pid in process.children) { @@ -161,7 +161,7 @@ namespace Monitor { } } - private bool match_process_app (Process process) { + private bool match_process_app (IProcess process) { var command_sanitized = ProcessUtils.sanitize_commandline (process.command); var command_sanitized_basename = Path.get_basename (command_sanitized); @@ -248,7 +248,7 @@ namespace Monitor { * * returns the created process */ - private Process ? add_process (int pid, bool lazy_signal = false) { + private IProcess ? add_process (int pid, bool lazy_signal = false) { // create the process var process = ProcessProvider.get_default ().create_process (pid); diff --git a/src/Managers/ProcessProvider.vala b/src/Managers/ProcessProvider.vala index 039b78fb..bf492bdd 100644 --- a/src/Managers/ProcessProvider.vala +++ b/src/Managers/ProcessProvider.vala @@ -53,7 +53,7 @@ namespace Monitor { return pids; } - public Process create_process (int pid) { + public IProcess create_process (int pid) { if (ProcessUtils.is_flatpak_env ()) { return new ProcessWorkaround (pid); } diff --git a/src/Managers/ProcessWorkaround.vala b/src/Managers/ProcessWorkaround.vala index 7a196d52..9bbd7473 100644 --- a/src/Managers/ProcessWorkaround.vala +++ b/src/Managers/ProcessWorkaround.vala @@ -1,11 +1,96 @@ -public class Monitor.ProcessWorkaround : Monitor.Process { +public class Monitor.ProcessWorkaround : IProcess, GLib.Object { + + // Whether or not the PID leads to something + public bool exists { get; private set; } + + // Full command from cmdline file + public string command { get; private set; } + + // If process is an installed app, this will contain its name, + // otherwise it is just a trimmed command + public string application_name { get; private set; } + + // User id + public int uid { get; private set; } + + public string username { get; private set; default = Utils.NO_DATA; } + + Icon _icon; + public Icon icon { + get { + return _icon; + } + set { + if (value == null) { + _icon = ProcessUtils.get_default_icon (); + } else { + _icon = value; + } + } + } + + // Contains info about io + public ProcessIO io { get; private set; } + + // Contains status info + public ProcessStatus stat { get; private set; } + + public ProcessStatusMemory statm { get; private set; } + + public Gee.HashSet open_files_paths { get; private set; } + + public Gee.HashSet children { get; private set; default = new Gee.HashSet (); } + + /** + * CPU usage of this process from the last time that it was updated, measured in percent + * + * Will be 0 on first update. + */ + public double cpu_percentage { get; private set; } + + private uint64 cpu_last_used { get; private set; } + + // Memory usage of the process, measured in KiB. + public uint64 mem_usage { get; private set; } + public double mem_percentage { get; private set; } + + private uint64 last_total { get; private set; } + + private const int HISTORY_BUFFER_SIZE = 30; + public Gee.ArrayList cpu_percentage_history { get; private set; default = new Gee.ArrayList (); } + public Gee.ArrayList mem_percentage_history { get; private set; default = new Gee.ArrayList (); } + + // Construct a new process public ProcessWorkaround (int _pid) { - base (_pid); + _icon = ProcessUtils.get_default_icon (); + + open_files_paths = new Gee.HashSet (); + + last_total = 0; + + io = {}; + stat = {}; + stat.pid = _pid; + + // getting uid + uid = get_uid (); + + // getting username + // @TOFIX: Can't get username for postgres which + // is started from docker (?) + unowned Posix.Passwd passwd = Posix.getpwuid (uid); + if (passwd != null) { + username = passwd.pw_name; + } + + exists = parse_stat () && read_cmdline (); + get_children_pids (); + get_usage (0, 1); } - private new int get_uid () { + private int get_uid () { var process_provider = ProcessProvider.get_default (); string ? status = process_provider.pids_status.get (this.stat.pid); var status_line = status.split ("\n"); @@ -13,7 +98,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { } // Kills the process - public new bool kill () { + public bool kill () { // Sends a kill signal that cannot be ignored if (Posix.kill (stat.pid, Posix.Signal.KILL) == 0) { return true; @@ -22,7 +107,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { } // Ends the process - public new bool end () { + public bool end () { // Sends a terminate signal if (Posix.kill (stat.pid, Posix.Signal.TERM) == 0) { return true; @@ -30,7 +115,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { return false; } - private new bool get_children_pids () { + private bool get_children_pids () { var process_provider = ProcessProvider.get_default (); string ? children_content = process_provider.pids_children.get (this.stat.pid); @@ -41,7 +126,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { return true; } - private new bool parse_io () { + private bool parse_io () { var process_provider = ProcessProvider.get_default (); string ? io_stats = process_provider.pids_io.get (this.stat.pid); @@ -82,7 +167,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { } // Reads the /proc/%pid%/stat file and updates the process with the information therein. - private new bool parse_stat () { + private bool parse_stat () { var process_provider = ProcessProvider.get_default (); string ? stat_contents = process_provider.pids_stat.get (this.stat.pid); @@ -120,7 +205,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { return true; } - private new bool parse_statm () { + private bool parse_statm () { var process_provider = ProcessProvider.get_default (); string ? statm_contents = process_provider.pids_stat.get (this.stat.pid); @@ -138,7 +223,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { return true; } - private new bool get_open_files () { + private bool get_open_files () { // try { // string directory = "/proc/%d/fd".printf (stat.pid); // Dir dir = Dir.open (directory, 0); @@ -165,7 +250,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { /** * Reads the /proc/%pid%/cmdline file and updates from the information contained therein. */ - private new bool read_cmdline () { + private bool read_cmdline () { var process_provider = ProcessProvider.get_default (); string ? cmdline = process_provider.pids_cmdline.get (this.stat.pid); @@ -186,7 +271,7 @@ public class Monitor.ProcessWorkaround : Monitor.Process { return true; } - private new void get_usage (uint64 cpu_total, uint64 cpu_last_total) { + private void get_usage (uint64 cpu_total, uint64 cpu_last_total) { // Get CPU usage by process GTop.ProcTime proc_time; GTop.get_proc_time (out proc_time, stat.pid); @@ -223,4 +308,17 @@ public class Monitor.ProcessWorkaround : Monitor.Process { mem_percentage_history.add (mem_percentage); } + // Updates the process to get latest information + // Returns if the update was successful + public bool update (uint64 cpu_total, uint64 cpu_last_total) { + exists = parse_stat (); + if (exists) { + get_usage (cpu_total, cpu_last_total); + parse_io (); + parse_statm (); + get_open_files (); + } + return exists; + } + } diff --git a/src/Models/OpenFilesTreeViewModel.vala b/src/Models/OpenFilesTreeViewModel.vala index 3769e599..6aeb5fc2 100644 --- a/src/Models/OpenFilesTreeViewModel.vala +++ b/src/Models/OpenFilesTreeViewModel.vala @@ -2,9 +2,9 @@ public class Monitor.OpenFilesTreeViewModel : Gtk.TreeStore { private Gee.Map open_files_paths = new Gee.HashMap (); - private Process _process; + private IProcess _process; - public Process ? process { + public IProcess ? process { get { return _process; } diff --git a/src/Models/TreeViewModel.vala b/src/Models/TreeViewModel.vala index 4394f823..fa7dc0d4 100644 --- a/src/Models/TreeViewModel.vala +++ b/src/Models/TreeViewModel.vala @@ -40,7 +40,7 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { } } - private bool add_process (Process process) { + private bool add_process (IProcess process) { if (process != null && !process_rows.has_key (process.stat.pid)) { debug ("Add process %d Parent PID: %d", process.stat.pid, process.stat.ppid); // add the process to the model @@ -69,7 +69,7 @@ public class Monitor.TreeViewModel : Gtk.TreeStore { private void update_model () { foreach (int pid in process_rows.keys) { - Process process = process_manager.get_process (pid); + IProcess process = process_manager.get_process (pid); Gtk.TreeIter iter = process_rows[pid]; set (iter, Column.CPU, process.cpu_percentage, diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala index 3e98578b..ec9fb06c 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala @@ -41,12 +41,12 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { attach (mem_graph_box, 1, 1, 1, 1); } - public void set_charts_data (Process process) { + public void set_charts_data (IProcess process) { cpu_chart.preset_data (0, process.cpu_percentage_history); ram_chart.preset_data (0, process.mem_percentage_history); } - public void update (Process process) { + public void update (IProcess process) { cpu_label.set_text ((_("CPU: %.1f%%")).printf (process.cpu_percentage)); ram_label.set_text ((_("RAM: %.1f%%")).printf (process.mem_percentage)); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala index 84f5aa43..1986988b 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala @@ -61,7 +61,7 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { attach (wrapper, 1, 1, 1, 1); } - public void update (Process process) { + public void update (IProcess process) { application_name.set_text (process.application_name); application_name.tooltip_text = process.command; pid.set_text (process.stat.pid.to_string ()); @@ -91,7 +91,7 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { set_icon (process); } - private void set_icon (Process process) { + private void set_icon (IProcess process) { // this construction should be somewhere else var icon_name = process.icon.to_string (); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala index 7576e021..0739ea1a 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala @@ -55,7 +55,7 @@ public class Monitor.ProcessInfoIOStats : Gtk.Grid { attach (open_files_tree_view_scrolled, 0, 4, 3, 1); } - public void update (Process process) { + public void update (IProcess process) { write_bytes_label.set_text (Utils.HumanUnitFormatter.double_bytes_to_human (process.io.write_bytes)); read_bytes_label.set_text (Utils.HumanUnitFormatter.double_bytes_to_human (process.io.read_bytes)); cancelled_write_bytes_label.set_text (Utils.HumanUnitFormatter.double_bytes_to_human (process.io.cancelled_write_bytes)); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 04fac337..8c570763 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -2,8 +2,8 @@ public class Monitor.ProcessInfoView : Gtk.Box { private Preventor preventor; private ProcessInfoIOStats process_info_io_stats = new ProcessInfoIOStats (); - private Process _process; - public Process ? process { + private IProcess _process; + public IProcess ? process { get { return _process; } diff --git a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala index 8cabe02b..95e2030d 100644 --- a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala +++ b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala @@ -6,7 +6,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { private Gtk.TreeViewColumn memory_column; private Regex ? regex; - public signal void process_selected (Process process); + public signal void process_selected (IProcess process); public CPUProcessTreeView (TreeViewModel model) { this.model = model; @@ -201,7 +201,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { if (selection != null) { tree_model.get_iter (out iter, selection); tree_model.get (iter, Column.PID, out pid); - Process process = model.process_manager.get_process (pid); + IProcess process = model.process_manager.get_process (pid); process_selected (process); // debug ("cursor changed"); } diff --git a/src/Views/ProcessView/ProcessView.vala b/src/Views/ProcessView/ProcessView.vala index 02cacbb2..910563b0 100644 --- a/src/Views/ProcessView/ProcessView.vala +++ b/src/Views/ProcessView/ProcessView.vala @@ -31,7 +31,7 @@ public class Monitor.ProcessView : Gtk.Box { add (paned); } - public void on_process_selected (Process process) { + public void on_process_selected (IProcess process) { process_info_view.process = process; process_info_view.no_show_all = false; // process_info_view.show_all (); diff --git a/src/meson.build b/src/meson.build index ec117034..1fd9993f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -59,7 +59,7 @@ source_app_files = [ 'Managers/Container.vala', 'Managers/ProcessProvider.vala', 'Managers/ProcessWorkaround.vala', - # 'Managers/IProcess.vala', + 'Managers/IProcess.vala', # Services 'Services/Shortcuts.vala',