summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorinfirit <[email protected]>2014-12-18 20:58:16 +0100
committerinfirit <[email protected]>2014-12-18 21:04:53 +0100
commit76eff089e1ba541cece59f6d2f5847f349448f89 (patch)
treea45acda13ac9ff08b898a9f98638a1ee4edcaf45
parent396b01dc3e3a704c0015874002b76a5ccda0678a (diff)
downloadmate-system-monitor-76eff089e1ba541cece59f6d2f5847f349448f89.tar.bz2
mate-system-monitor-76eff089e1ba541cece59f6d2f5847f349448f89.tar.xz
Add cgroup support in the process view
Add a new 'Control Group' column to the process view tab. The format for the column is: <path name> (controller name), <path name> (controller name)... Processes that share the same path name across controllers are colesced. For example if a process is in the /foo cgroup for both the memory and cpu controllers, it would display as: /foo (memory,cpu), ... Taken from GSM commits: 2d33adcbc4347c112d57082956b4e199ff7132db Add cgroup support in the process view 645d38a218fedcbf9c7b674740bf213e02933820 Optimize cgroup updating From: Jason Baron <[email protected]>
-rw-r--r--src/Makefile.am1
-rw-r--r--src/cgroups.cpp186
-rw-r--r--src/cgroups.h14
-rw-r--r--src/org.mate.system-monitor.gschema.xml.in.in8
-rw-r--r--src/procdialogs.cpp6
-rw-r--r--src/procman.h1
-rw-r--r--src/proctable.cpp21
-rw-r--r--src/proctable.h1
8 files changed, 236 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index efea297..ff9f2a8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -25,6 +25,7 @@ mate_system_monitor_SOURCES = \
defaulttable.h \
disks.cpp disks.h \
selinux.h selinux.cpp \
+ cgroups.h cgroups.cpp \
procman_matesu.h procman_matesu.cpp \
procman_gksu.h procman_gksu.cpp \
sysinfo.cpp sysinfo.h \
diff --git a/src/cgroups.cpp b/src/cgroups.cpp
new file mode 100644
index 0000000..eafa1e3
--- /dev/null
+++ b/src/cgroups.cpp
@@ -0,0 +1,186 @@
+#include <config.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include "procman.h"
+#include "util.h"
+
+gboolean
+cgroups_enabled(void)
+{
+ static gboolean initialized = FALSE;
+ static gboolean has_cgroups;
+
+ if (!initialized) {
+ initialized = TRUE;
+ has_cgroups = g_file_test("/proc/cgroups", G_FILE_TEST_EXISTS);
+ }
+
+ return has_cgroups;
+}
+
+void
+append_cgroup_name(char *line, gchar **current_cgroup_name)
+{
+ gchar *controller, *path, *tmp, *path_plus_space;
+ int paren_offset, off, tmp_size;
+
+ controller = g_strstr_len(line, -1, ":") + 1;
+ if (!controller)
+ return;
+
+ path = g_strstr_len(controller, -1, ":") + 1;
+ if (!path)
+ return;
+
+ *(path - 1) = '\0';
+ g_strdelimit(controller, ",", '/');
+
+ if ((std::strcmp(path, "/") == 0) || (std::strncmp(controller, "name=", 5) == 0))
+ return;
+
+ if (*current_cgroup_name == NULL) {
+ *current_cgroup_name = g_strdup_printf("%s (%s)", path, controller);
+ return;
+ }
+
+ /* add a space to the end of the path string */
+ path_plus_space = g_strdup_printf("%s ", path);
+
+ if ((tmp = g_strstr_len(*current_cgroup_name, -1, path_plus_space))) {
+ tmp_size = strlen(*current_cgroup_name) + strlen(controller) + 1;
+ paren_offset = g_strstr_len(tmp + strlen(path), -1, ")") - *current_cgroup_name;
+ *(*current_cgroup_name + paren_offset) = '\0';
+ tmp = (gchar *)g_strnfill(tmp_size, '\0');
+ off = g_strlcat(tmp, *current_cgroup_name, tmp_size);
+ *(tmp + off) = '/';
+ off++;
+ off += g_strlcat(tmp + off, controller, tmp_size);
+ *(tmp + off) = ')';
+ off++;
+ g_strlcat(tmp + off, *current_cgroup_name + paren_offset + 1, tmp_size);
+ } else
+ tmp = g_strdup_printf("%s, %s(%s)", *current_cgroup_name, path_plus_space, controller);
+
+ g_free(path_plus_space);
+ g_free(*current_cgroup_name);
+ *current_cgroup_name = tmp;
+}
+
+int
+check_cgroup_changed(gchar *line, gchar *current_cgroup_set)
+{
+ /* check if line is contained in current_cgroup_set */
+ gchar *controller, *path, *tmp, *found, *close_paren, *open_paren;
+ int ret = 0;
+
+ controller = g_strstr_len(line, -1, ":") + 1;
+ if (!controller)
+ return 1;
+
+ path = g_strstr_len(controller, -1, ":") + 1;
+ if (!path)
+ return 1;
+
+ *(path - 1) = '\0';
+
+ if (std::strncmp(controller, "name=", 5) == 0)
+ goto out;
+
+ /* if there are multiple controllers just report string has changed */
+ if (g_strstr_len(controller, -1, ",")) {
+ ret = 1;
+ goto out;
+ }
+
+ if (!current_cgroup_set) {
+ if (std::strcmp(path, "/") != 0)
+ ret = 1;
+ goto out;
+ }
+
+ /* special case for root cgroup */
+ tmp = current_cgroup_set;
+ if (std::strcmp(path, "/") == 0) {
+ while ((found = g_strstr_len(tmp, -1, controller))) {
+ close_paren = g_strstr_len(found, -1, ")");
+ open_paren = g_strstr_len(found, -1, "(");
+ if (close_paren) {
+ if (!open_paren || (close_paren < open_paren)) {
+ ret = 1;
+ goto out;
+ }
+ }
+ tmp = found + strlen(controller);
+ }
+ goto out;
+ }
+
+ tmp = current_cgroup_set;
+ while ((found = g_strstr_len(tmp, -1, path))) {
+ found = found + strlen(path);
+ close_paren = g_strstr_len(found, -1, ")");
+ if (*found == ' ') {
+ if (g_strstr_len(found + 1, close_paren - found, controller))
+ goto out;
+ }
+ tmp = close_paren + 1;
+ }
+ ret = 1;
+out:
+ *(path - 1) = ':';
+ return ret;
+}
+
+void
+get_process_cgroup_info(ProcInfo *info)
+{
+ gchar *path;
+ gchar *cgroup_name = NULL;
+ int cgroups_changed = 0;
+ gchar *text;
+ char **lines;
+ int i;
+
+ if (!cgroups_enabled())
+ return;
+
+ /* read out of /proc/pid/cgroup */
+ path = g_strdup_printf("/proc/%d/cgroup", info->pid);
+ if (!path)
+ return;
+ if(!g_file_get_contents(path, &text, NULL, NULL))
+ goto out;
+ lines = g_strsplit(text, "\n", -1);
+ g_free(text);
+ if (!lines)
+ goto out;
+
+ for (i = 0; lines[i] != NULL; i++) {
+ if (lines[i][0] == '\0')
+ continue;
+ if (check_cgroup_changed(lines[i], info->cgroup_name)) {
+ cgroups_changed = 1;
+ break;
+ }
+ }
+
+ if (cgroups_changed) {
+ for (i = 0; lines[i] != NULL; i++) {
+ if (lines[i][0] == '\0')
+ continue;
+ append_cgroup_name(lines[i], &cgroup_name);
+ }
+ if (info->cgroup_name)
+ g_free(info->cgroup_name);
+ if (!cgroup_name)
+ info->cgroup_name = g_strdup("");
+ else
+ info->cgroup_name = cgroup_name;
+ }
+
+ g_strfreev(lines);
+out:
+ g_free(path);
+}
diff --git a/src/cgroups.h b/src/cgroups.h
new file mode 100644
index 0000000..8c42f6f
--- /dev/null
+++ b/src/cgroups.h
@@ -0,0 +1,14 @@
+#ifndef PROCMAN_CGROUP_H_20111103
+#define PROCMAN_CGROUP_H_20111103
+
+#include <glib.h>
+
+#include "procman.h"
+
+void
+get_process_cgroup_info (ProcInfo *info);
+
+gboolean
+cgroups_enabled (void);
+
+#endif /* PROCMAN_CGROUP_H_20111103 */
diff --git a/src/org.mate.system-monitor.gschema.xml.in.in b/src/org.mate.system-monitor.gschema.xml.in.in
index 7abcd11..39f4f09 100644
--- a/src/org.mate.system-monitor.gschema.xml.in.in
+++ b/src/org.mate.system-monitor.gschema.xml.in.in
@@ -287,6 +287,14 @@
<default>true</default>
<_summary>Show process 'Waiting Channel' column on startup</_summary>
</key>
+ <key name="col-17-width" type="i">
+ <default>48</default>
+ <_summary>Width of process 'Control Group' column</_summary>
+ </key>
+ <key name="col-17-visible" type="b">
+ <default>false</default>
+ <_summary>Show process 'Control Group' column on startup</_summary>
+ </key>
</schema>
<schema gettext-domain="@GETTEXT_PACKAGE@" id="org.mate.system-monitor.disktreenew" path="/org/mate/system-monitor/disktreenew/">
<key name="sort-col" type="i">
diff --git a/src/procdialogs.cpp b/src/procdialogs.cpp
index 449679d..d129bd9 100644
--- a/src/procdialogs.cpp
+++ b/src/procdialogs.cpp
@@ -34,6 +34,7 @@
#include "settings-keys.h"
#include "procman_matesu.h"
#include "procman_gksu.h"
+#include "cgroups.h"
static GtkWidget *renice_dialog = NULL;
static GtkWidget *prefs_dialog = NULL;
@@ -470,11 +471,16 @@ create_field_page(GtkWidget *tree, const char* text)
GtkTreeIter iter;
const gchar *title;
gboolean visible;
+ gint column_id;
title = gtk_tree_view_column_get_title (column);
if (!title)
title = _("Icon");
+ column_id = gtk_tree_view_column_get_sort_column_id(column);
+ if ((column_id == COL_CGROUP) && (!cgroups_enabled()))
+ continue;
+
visible = gtk_tree_view_column_get_visible (column);
gtk_list_store_append (model, &iter);
diff --git a/src/procman.h b/src/procman.h
index f359667..2adfb7d 100644
--- a/src/procman.h
+++ b/src/procman.h
@@ -126,6 +126,7 @@ MutableProcInfo()
guint status;
guint pcpu;
gint nice;
+ gchar *cgroup_name;
};
diff --git a/src/proctable.cpp b/src/proctable.cpp
index 6824124..13a4fa4 100644
--- a/src/proctable.cpp
+++ b/src/proctable.cpp
@@ -52,6 +52,7 @@
#include "util.h"
#include "interface.h"
#include "selinux.h"
+#include "cgroups.h"
ProcInfo::UserMap ProcInfo::users;
@@ -258,6 +259,7 @@ proctable_new (ProcData * const procdata)
N_("Memory"),
/* xgettext: wchan, see ps(1) or top(1) */
N_("Waiting Channel"),
+ N_("Control Group"),
NULL,
"POINTER"
};
@@ -287,6 +289,7 @@ proctable_new (ProcData * const procdata)
G_TYPE_STRING, /* Arguments */
G_TYPE_ULONG, /* Memory */
G_TYPE_STRING, /* wchan */
+ G_TYPE_STRING, /* Cgroup */
GDK_TYPE_PIXBUF, /* Icon */
G_TYPE_POINTER, /* ProcInfo */
G_TYPE_STRING /* Sexy tooltip */
@@ -330,7 +333,7 @@ proctable_new (ProcData * const procdata)
gtk_tree_view_set_expander_column (GTK_TREE_VIEW (proctree), column);
- for (i = COL_USER; i <= COL_WCHAN; i++) {
+ for (i = COL_USER; i <= COL_CGROUP; i++) {
GtkCellRenderer *cell;
GtkTreeViewColumn *col;
@@ -435,6 +438,14 @@ proctable_new (ProcData * const procdata)
gtk_tree_view_column_set_visible (column, FALSE);
}
+ if (!cgroups_enabled()) {
+ GtkTreeViewColumn *column;
+
+ column = my_gtk_tree_view_get_column_with_sort_column_id(GTK_TREE_VIEW(proctree), COL_CGROUP);
+ gtk_tree_view_column_set_visible(column, FALSE);
+ }
+
+
g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (proctree))),
"changed",
G_CALLBACK (cb_row_selected), procdata);
@@ -459,6 +470,7 @@ ProcInfo::~ProcInfo()
g_free(this->tooltip);
g_free(this->arguments);
g_free(this->security_context);
+ g_free(this->cgroup_name);
}
@@ -544,7 +556,6 @@ static void get_process_memory_writable(ProcInfo *info)
g_free(maps);
}
-
static void
get_process_memory_info(ProcInfo *info)
{
@@ -593,6 +604,7 @@ update_info_mutable_cols(ProcInfo *info)
tree_store_update(model, &info->node, COL_NICE, info->nice);
tree_store_update(model, &info->node, COL_MEM, info->mem);
tree_store_update(model, &info->node, COL_WCHAN, info->wchan);
+ tree_store_update(model, &info->node, COL_CGROUP, info->cgroup_name);
}
@@ -709,6 +721,9 @@ update_info (ProcData *procdata, ProcInfo *info)
ProcInfo::cpu_times[info->pid] = info->cpu_time = proctime.rtime;
info->nice = procuid.nice;
info->ppid = procuid.ppid;
+
+ /* get cgroup data */
+ get_process_cgroup_info(info);
}
@@ -753,6 +768,8 @@ ProcInfo::ProcInfo(pid_t pid)
info->start_time = proctime.start_time;
get_process_selinux_context (info);
+ info->cgroup_name = NULL;
+ get_process_cgroup_info(info);
}
diff --git a/src/proctable.h b/src/proctable.h
index 9c90669..0811c61 100644
--- a/src/proctable.h
+++ b/src/proctable.h
@@ -43,6 +43,7 @@ enum
COL_ARGS,
COL_MEM,
COL_WCHAN,
+ COL_CGROUP,
COL_PIXBUF,
COL_POINTER,
COL_TOOLTIP,