From a02bf695731de0e02b21ff2a977afaf5ac67214c Mon Sep 17 00:00:00 2001 From: Mike Massonnet Date: Wed, 5 May 2010 08:53:49 +0200 Subject: [PATCH] Show list of tasks Provide the list of tasks through a GArray and parse it in main.c to update the GtkTreeModel. --- src/main.c | 122 +++++++++++++++++++++++++- src/process-tree-view.c | 115 +++++++----------------- src/process-tree-view.h | 17 ++++ src/task-manager-linux.c | 185 +++++++++++++++++++++++++++++++++++++-- src/task-manager.c | 90 +++++++++++++++++-- src/task-manager.h | 26 +++--- 6 files changed, 443 insertions(+), 112 deletions(-) diff --git a/src/main.c b/src/main.c index 5fac70f..2659c33 100644 --- a/src/main.c +++ b/src/main.c @@ -12,21 +12,137 @@ #include #endif +#include #include #include "process-window.h" +#include "process-tree-view.h" #include "task-manager.h" static GtkWidget *window; static XtmTaskManager *task_manager; +static gboolean timeout = 0; + +static void +update_tree_iter (GtkTreeModel *model, GtkTreeIter *iter, Task *task) +{ + gchar vsz[64], rss[64], cpu[16]; + + // TODO add precision for values < 1 MB + g_snprintf (vsz, 64, _("%lu MB"), task->vsz / 1024 / 1024); + g_snprintf (rss, 64, _("%lu MB"), task->rss / 1024 / 1024); + // TODO make precision optional + g_snprintf (cpu, 16, _("%.2f%%"), task->cpu_user + task->cpu_system); + + gtk_list_store_set (GTK_LIST_STORE (model), iter, + XTM_PTV_COLUMN_PPID, task->ppid, + XTM_PTV_COLUMN_STATE, task->state, + XTM_PTV_COLUMN_VSZ, task->vsz, + XTM_PTV_COLUMN_VSZ_STR, vsz, + XTM_PTV_COLUMN_RSS, task->rss, + XTM_PTV_COLUMN_RSS_STR, rss, + XTM_PTV_COLUMN_CPU, task->cpu_user + task->cpu_system, + XTM_PTV_COLUMN_CPU_STR, cpu, + XTM_PTV_COLUMN_PRIORITY, task->prio, + -1); +} + +static void +add_tree_iter (GtkTreeModel *model, Task *task) +{ + GtkTreeIter iter; + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + XTM_PTV_COLUMN_COMMAND, task->cmdline, + XTM_PTV_COLUMN_PID, task->pid, + XTM_PTV_COLUMN_STATE, task->state, + XTM_PTV_COLUMN_UID, task->uid_name, + -1); + update_tree_iter (model, &iter, task); +} + +static void +update_tree_model (const GArray *task_list) +{ + GtkTreeModel *model; + GtkTreeIter iter; + Task *task; + guint i; + gboolean valid; + + model = xtm_process_window_get_model (XTM_PROCESS_WINDOW (window)); + + // TODO pick a timestamp for started/terminated tasks to keep them momentary (red/green color, italic, ...) + /* Remove terminated tasks */ + valid = gtk_tree_model_get_iter_first (model, &iter); + while (valid) + { + guint pid; + gboolean found = FALSE; + + gtk_tree_model_get (model, &iter, XTM_PTV_COLUMN_PID, &pid, -1); + for (i = 0; i < task_list->len; i++) + { + task = &g_array_index (task_list, Task, i); + if (pid != task->pid) + continue; + found = TRUE; + break; + } + + if (found == FALSE) + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + + valid = gtk_tree_model_iter_next (model, &iter); + } + + /* Append started tasks and update existing ones */ + for (i = 0; i < task_list->len; i++) + { + guint pid; + gboolean found = FALSE; + + task = &g_array_index (task_list, Task, i); + valid = gtk_tree_model_get_iter_first (model, &iter); + while (valid) + { + gtk_tree_model_get (model, &iter, XTM_PTV_COLUMN_PID, &pid, -1); + + if (pid == task->pid) + { + // TODO check if elements have to be updated, updating everything always is a CPU hog + update_tree_iter (model, &iter, task); + found = TRUE; + break; + } + + valid = gtk_tree_model_iter_next (model, &iter); + } + + if (found == FALSE) + { + add_tree_iter (model, task); + } + } +} static gboolean -timeout_cb () +init_timeout () { guint num_processes; gfloat cpu, memory, swap; + const GArray *task_list; + xtm_task_manager_get_system_info (task_manager, &num_processes, &cpu, &memory, &swap); xtm_process_window_set_system_info (XTM_PROCESS_WINDOW (window), num_processes, cpu, memory, swap); + + task_list = xtm_task_manager_get_task_list (task_manager); + update_tree_model (task_list); + + if (timeout == 0) + timeout = g_timeout_add (1000, init_timeout, NULL); + + return TRUE; } int main (int argc, char *argv[]) @@ -45,12 +161,14 @@ int main (int argc, char *argv[]) task_manager = xtm_task_manager_new (); g_message ("Running as %s on %s", xtm_task_manager_get_username (task_manager), xtm_task_manager_get_hostname (task_manager)); - g_timeout_add (1000, timeout_cb, NULL); + init_timeout (); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); gtk_main (); + if (timeout > 0) + g_source_remove (timeout); g_object_unref (window); return 0; diff --git a/src/process-tree-view.c b/src/process-tree-view.c index e649f58..450681b 100644 --- a/src/process-tree-view.c +++ b/src/process-tree-view.c @@ -34,20 +34,6 @@ struct _XtmProcessTreeView }; G_DEFINE_TYPE (XtmProcessTreeView, xtm_process_tree_view, GTK_TYPE_TREE_VIEW) -enum -{ - COLUMN_COMMAND, - COLUMN_PID, - COLUMN_PPID, - COLUMN_STATE, - COLUMN_VSZ, - COLUMN_RSS, - COLUMN_UID, - COLUMN_CPU, - COLUMN_PRIORITY, - N_COLUMNS, -}; - static gboolean treeview_clicked (XtmProcessTreeView *treeview, GdkEventButton *event); static void settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treeview); static int sort_by_string (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data); @@ -74,10 +60,10 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview) g_object_get (treeview->settings, "sort-column-id", &sort_column_id, "sort-type", &sort_type, NULL); g_signal_connect (treeview->settings, "notify", G_CALLBACK (settings_changed), treeview); - treeview->model = gtk_list_store_new (9, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + treeview->model = gtk_list_store_new (XTM_PTV_N_COLUMNS, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT64, + G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_FLOAT, G_TYPE_STRING, G_TYPE_INT); - g_object_set (treeview, "search-column", COLUMN_COMMAND, "model", treeview->model, NULL); + g_object_set (treeview, "search-column", XTM_PTV_COLUMN_COMMAND, "model", treeview->model, NULL); cell_text = gtk_cell_renderer_text_new(); @@ -87,61 +73,60 @@ xtm_process_tree_view_init (XtmProcessTreeView *treeview) cell_cmdline = gtk_cell_renderer_text_new (); g_object_set (cell_cmdline, "ellipsize", PANGO_ELLIPSIZE_END, NULL); - column = gtk_tree_view_column_new_with_attributes (_("Task"), cell_cmdline, "text", COLUMN_COMMAND, NULL); + column = gtk_tree_view_column_new_with_attributes (_("Task"), cell_cmdline, "text", XTM_PTV_COLUMN_COMMAND, NULL); g_object_set (column, "expand", TRUE, "reorderable", FALSE, "resizable", TRUE, "visible", TRUE, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_COMMAND); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_COMMAND); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-pid", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("PID"), cell_right_aligned, "text", COLUMN_PID, NULL); + column = gtk_tree_view_column_new_with_attributes (_("PID"), cell_right_aligned, "text", XTM_PTV_COLUMN_PID, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PID); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_PID); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-ppid", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("PPID"), cell_right_aligned, "text", COLUMN_PPID, NULL); + column = gtk_tree_view_column_new_with_attributes (_("PPID"), cell_right_aligned, "text", XTM_PTV_COLUMN_PPID, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PPID); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_PPID); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-state", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("State"), cell_text, "text", COLUMN_STATE, NULL); + column = gtk_tree_view_column_new_with_attributes (_("State"), cell_text, "text", XTM_PTV_COLUMN_STATE, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_STATE); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_STATE); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-vsz", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("VSZ"), cell_right_aligned, "text", COLUMN_VSZ, NULL); + column = gtk_tree_view_column_new_with_attributes (_("VSZ"), cell_right_aligned, "text", XTM_PTV_COLUMN_VSZ_STR, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_VSZ); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_VSZ); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-rss", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("RSS"), cell_right_aligned, "text", COLUMN_RSS, NULL); + column = gtk_tree_view_column_new_with_attributes (_("RSS"), cell_right_aligned, "text", XTM_PTV_COLUMN_RSS_STR, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_RSS); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_RSS); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-uid", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("UID"), cell_text, "text", COLUMN_UID, NULL); + column = gtk_tree_view_column_new_with_attributes (_("UID"), cell_text, "text", XTM_PTV_COLUMN_UID, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_UID); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_UID); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-cpu", &visible, NULL); - column = gtk_tree_view_column_new_with_attributes (_("CPU"), cell_right_aligned, "text", COLUMN_CPU, NULL); + column = gtk_tree_view_column_new_with_attributes (_("CPU"), cell_right_aligned, "text", XTM_PTV_COLUMN_CPU_STR, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_CPU); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_CPU); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); g_object_get (treeview->settings, "column-priority", &visible, NULL); /* TRANSLATORS: “Prio.” is short for Priority, it appears in the tree view header. */ - column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", COLUMN_PRIORITY, NULL); + column = gtk_tree_view_column_new_with_attributes (_("Prio."), cell_right_aligned, "text", XTM_PTV_COLUMN_PRIORITY, NULL); g_object_set (column, "expand", FALSE, "reorderable", FALSE, "resizable", TRUE, "visible", visible, NULL); - gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), COLUMN_PRIORITY); + gtk_tree_view_column_set_sort_column_id (GTK_TREE_VIEW_COLUMN (column), XTM_PTV_COLUMN_PRIORITY); gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column); - gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (treeview->model), sort_by_string, NULL, NULL); gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (treeview->model), sort_column_id, sort_type); g_signal_connect (treeview, "button-press-event", G_CALLBACK (treeview_clicked), NULL); @@ -165,27 +150,27 @@ treeview_clicked (XtmProcessTreeView *treeview, GdkEventButton *event) static void settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treeview) { - if (g_strstr_len (pspec->name, -1, "column-") != NULL) + if (g_str_has_prefix (pspec->name, "column-")) { gboolean visible; gushort column_id; if (!g_strcmp0 (pspec->name, "column-uid")) - column_id = COLUMN_UID; + column_id = XTM_PTV_COLUMN_UID; else if (!g_strcmp0 (pspec->name, "column-pid")) - column_id = COLUMN_PID; + column_id = XTM_PTV_COLUMN_PID; else if (!g_strcmp0 (pspec->name, "column-ppid")) - column_id = COLUMN_PPID; + column_id = XTM_PTV_COLUMN_PPID; else if (!g_strcmp0 (pspec->name, "column-state")) - column_id = COLUMN_STATE; + column_id = XTM_PTV_COLUMN_STATE; else if (!g_strcmp0 (pspec->name, "column-vsz")) - column_id = COLUMN_VSZ; + column_id = XTM_PTV_COLUMN_VSZ_STR; else if (!g_strcmp0 (pspec->name, "column-rss")) - column_id = COLUMN_RSS; + column_id = XTM_PTV_COLUMN_RSS_STR; else if (!g_strcmp0 (pspec->name, "column-cpu")) - column_id = COLUMN_CPU; + column_id = XTM_PTV_COLUMN_CPU_STR; else if (!g_strcmp0 (pspec->name, "column-priority")) - column_id = COLUMN_PRIORITY; + column_id = XTM_PTV_COLUMN_PRIORITY; g_object_get (object, pspec->name, &visible, NULL); gtk_tree_view_column_set_visible (gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), column_id), visible); @@ -198,46 +183,6 @@ settings_changed (GObject *object, GParamSpec *pspec, XtmProcessTreeView *treevi } } -static int -sort_by_string (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) -{ - gint sort_column_id; - GtkSortType order; - gchar *str1 = NULL, *str2 = NULL; - gchar *cstr1 = NULL, *cstr2 = NULL; - gint ret = 0; - - g_debug (__func__); - - if (!gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model), &sort_column_id, &order)) - { - g_debug ("sort column default or unsorted: %d", sort_column_id); - return ret; - } - - gtk_tree_model_get(model, a, sort_column_id, &str1, -1); - gtk_tree_model_get(model, b, sort_column_id, &str2, -1); - - cstr1 = g_utf8_collate_key_for_filename (str1, -1); - cstr2 = g_utf8_collate_key_for_filename (str2, -1); - - if (cstr1 != NULL && cstr2 != NULL) - { - ret = g_utf8_collate (cstr1, cstr2); - } - else if ((cstr1 == NULL && cstr2 != NULL) || (cstr1 != NULL && cstr2 == NULL)) - { - ret = (cstr1 == NULL) ? -1 : 1; - } - - g_free (str1); - g_free (str2); - g_free (cstr1); - g_free (cstr2); - - return ret; -} - GtkWidget * diff --git a/src/process-tree-view.h b/src/process-tree-view.h index 71db963..481c552 100644 --- a/src/process-tree-view.h +++ b/src/process-tree-view.h @@ -16,6 +16,23 @@ #include +enum +{ + XTM_PTV_COLUMN_COMMAND, + XTM_PTV_COLUMN_PID, + XTM_PTV_COLUMN_PPID, + XTM_PTV_COLUMN_STATE, + XTM_PTV_COLUMN_VSZ, + XTM_PTV_COLUMN_VSZ_STR, + XTM_PTV_COLUMN_RSS, + XTM_PTV_COLUMN_RSS_STR, + XTM_PTV_COLUMN_UID, + XTM_PTV_COLUMN_CPU, + XTM_PTV_COLUMN_CPU_STR, + XTM_PTV_COLUMN_PRIORITY, + XTM_PTV_N_COLUMNS, +}; + #define XTM_TYPE_PROCESS_TREE_VIEW (xtm_process_tree_view_get_type ()) #define XTM_PROCESS_TREE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeView)) #define XTM_PROCESS_TREE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XTM_TYPE_PROCESS_TREE_VIEW, XtmProcessTreeViewClass)) diff --git a/src/task-manager-linux.c b/src/task-manager-linux.c index c207a11..d006bde 100644 --- a/src/task-manager-linux.c +++ b/src/task-manager-linux.c @@ -9,11 +9,18 @@ */ #include +#include +#include +#include +#include +#include #include #include "task-manager.h" +static gushort _cpu_count = 0; + gboolean get_memory_usage (guint64 *memory_total, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free) { @@ -23,9 +30,7 @@ get_memory_usage (guint64 *memory_total, guint64 *memory_free, guint64 *memory_c gushort found = 0; if ((file = fopen (filename, "r")) == NULL) - { return FALSE; - } while (found < 6 && fgets (buffer, 1024, file) != NULL) { @@ -58,21 +63,19 @@ get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system) static gulong cur_jiffies_system = 0, old_jiffies_system = 0; static gulong cur_jiffies = 0, old_jiffies = 0; gulong user, user_nice, system, idle; - gushort count = 0; if ((file = fopen (filename, "r")) == NULL) - { return FALSE; - } fgets (buffer, 1024, file); sscanf (buffer, "cpu\t%u %u %u %u", &user, &user_nice, &system, &idle); + _cpu_count = 0; while (fgets (buffer, 1024, file) != NULL) { if (buffer[0] != 'c' && buffer[1] != 'p' && buffer[2] != 'u') break; - count += 1; + _cpu_count += 1; } fclose (file); @@ -86,7 +89,175 @@ get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system) *cpu_user = (old_jiffies > 0) ? (cur_jiffies_user - old_jiffies_user) * 100 / (gdouble)(cur_jiffies - old_jiffies) : 0; *cpu_system = (old_jiffies > 0) ? (cur_jiffies_system - old_jiffies_system) * 100 / (gdouble)(cur_jiffies - old_jiffies) : 0; - *cpu_count = (count != 0) ? count : 1; + *cpu_count = (_cpu_count > 0) ? _cpu_count : 1; + _cpu_count = *cpu_count; + + return TRUE; +} + +static inline int get_pagesize () +{ + static int pagesize = 0; + if (pagesize == 0) + { + pagesize = sysconf (_SC_PAGESIZE); + if (pagesize == 0) + pagesize = 4096; + } + return pagesize; +} + +static void +get_task_cmdline (Task *task) +{ + FILE *file; + gchar filename[96]; + gint i; + gchar c; + + snprintf (filename, 96, "/proc/%i/cmdline", task->pid); + if ((file = fopen (filename, "r")) == NULL) + return; + + /* Drop parentheses around task->name */ + // FIXME comm concats the name to 15 chars + { + gchar *p; + g_strlcpy (task->name, &task->name[1], sizeof (task->name)); + p = g_strrstr (task->name, ")"); + *p = '\0'; + } + + /* Read byte per byte until EOF */ + for (i = 0; (c = fgetc (file)) != EOF && i < sizeof (task->cmdline) - 1; i++) + task->cmdline[i] = (c == '\0') ? ' ' : c; + if (task->cmdline[i-1] == ' ') + task->cmdline[i-1] = '\0'; + fclose (file); + + /* Kernel processes don't have a cmdline nor an exec path */ + if (i == 0) + { + size_t len = strlen (task->name); + g_strlcpy (&task->cmdline[1], task->name, len + 1); + task->cmdline[0] = '['; + task->cmdline[len+1] = ']'; + task->cmdline[len+2] = '\0'; + } +} + +static gboolean +get_task_details (guint pid, Task *task) +{ + FILE *file; + gchar filename[96]; + gchar buffer[1024]; + + snprintf (filename, 96, "/proc/%d/stat", pid); + if ((file = fopen (filename, "r")) == NULL) + return FALSE; + + fgets (buffer, 1024, file); + fclose (file); + + { + gchar dummy[255]; + gint idummy; + static gulong cur_j_user, cur_j_system; + static gulong old_j_user, old_j_system; + struct passwd *pw; + struct stat sstat; + + sscanf(buffer, "%i %255s %1s %i %i %i %i %i %255s %255s %255s %255s %255s %i %i %i %i %i %i %i %i %i %i %i %255s %255s %255s %i %255s %255s %255s %255s %255s %255s %255s %255s %255s %255s %i %255s %255s", + &task->pid, // processid + task->name, // processname + task->state, // processstate + &task->ppid, // parentid + &idummy, // processs groupid + + &idummy, // session id + &idummy, // tty id + &idummy, // tpgid the process group ID of the process running on tty of the process + dummy, // flags + dummy, // minflt minor faults the process has maid + + dummy, // cminflt + dummy, // majflt + dummy, // cmajflt + &cur_j_user, // utime the number of jiffies that this process has scheduled in user mode + &cur_j_system, // stime " system mode + + &idummy, // cutime " waited for children in user mode + &idummy, // cstime " system mode + &idummy, // priority (nice value + fifteen) + &task->prio, // nice range from 19 to -19 + &idummy, // hardcoded 0 + + &idummy, // itrealvalue time in jiffies to next SIGALRM send to this process + &idummy, // starttime jiffies the process startet after system boot + &task->vsz, // vsize in bytes + &task->rss, // rss (number of pages in real memory) + dummy, // rlim limit in bytes for rss + + dummy, // startcode + dummy, // endcode + &idummy, // startstack + dummy, // kstkesp value of esp (stack pointer) + dummy, // kstkeip value of EIP (instruction pointer) + + dummy, // signal. bitmap of pending signals + dummy, // blocked: bitmap of blocked signals + dummy, // sigignore: bitmap of ignored signals + dummy, // sigcatch: bitmap of catched signals + dummy, // wchan + + dummy, // nswap + dummy, // cnswap + dummy, // exit_signal + &idummy, // CPU number last executed on + dummy, + + dummy + ); + + task->rss *= get_pagesize (); + task->cpu_user = (old_j_user > 0 && _cpu_count > 0) ? (cur_j_user - old_j_user) / (gfloat)_cpu_count : 0; + task->cpu_system = (old_j_system > 0 && _cpu_count > 0) ? (cur_j_system - old_j_system) / (gfloat)_cpu_count : 0; + + stat (filename, &sstat); + pw = getpwuid (sstat.st_uid); + task->uid = sstat.st_uid; + g_strlcpy (task->uid_name, (pw != NULL) ? pw->pw_name : "nobody", sizeof (task->uid_name)); + } + + get_task_cmdline (task); + + return TRUE; +} + +gboolean +get_task_list (GArray *task_list) +{ + GDir *dir; + const gchar *name; + guint pid; + Task task = { 0 }; + + if ((dir = g_dir_open ("/proc", 0, NULL)) == NULL) + return FALSE; + + while ((name = g_dir_read_name(dir)) != NULL) + { + if ((pid = (guint)g_ascii_strtoull (name, NULL, 0)) > 0) + { + if (get_task_details (pid, &task)) + { + g_array_append_val (task_list, task); + } + } + } + + g_dir_close (dir); return TRUE; } diff --git a/src/task-manager.c b/src/task-manager.c index ca5de7d..c12696a 100644 --- a/src/task-manager.c +++ b/src/task-manager.c @@ -66,6 +66,7 @@ xtm_task_manager_class_init (XtmTaskManagerClass *klass) static void xtm_task_manager_init (XtmTaskManager *manager) { + manager->tasks = g_array_new (FALSE, FALSE, sizeof (Task)); get_owner_uid (&(manager->owner_uid), &(manager->owner_uid_name)); manager->hostname = get_hostname (); } @@ -74,6 +75,7 @@ static void xtm_task_manager_finalize (GObject *object) { XtmTaskManager *manager = XTM_TASK_MANAGER (object); + g_array_free (manager->tasks, TRUE); g_free (manager->owner_uid_name); g_free (manager->hostname); } @@ -128,18 +130,13 @@ xtm_task_manager_get_hostname (XtmTaskManager *manager) return manager->hostname; } -GArray * -xtm_task_manager_get_tasklist (XtmTaskManager *manager) -{ -} - void xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu, gfloat *memory, gfloat *swap) { guint64 memory_used, swap_used; /* Set number of processes */ - *num_processes = 0;//manager->tasks->len; + *num_processes = manager->tasks->len; /* Set memory and swap usage */ get_memory_usage (&manager->memory_total, &manager->memory_free, &manager->memory_cache, &manager->memory_buffers, @@ -156,6 +153,87 @@ xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, *cpu = manager->cpu_user + manager->cpu_system; } +const GArray * +xtm_task_manager_get_task_list (XtmTaskManager *manager) +{ + GArray *array; + guint i; + + if (manager->tasks->len == 0) + { + get_task_list (manager->tasks); +#if 1|DEBUG + { + gint i; + for (i = 0; i < manager->tasks->len; i++) + { + Task *task = &g_array_index (manager->tasks, Task, i); + g_print ("%5d %5s %15s %.50s\n", task->pid, task->uid_name, task->name, task->cmdline); + } + } +#endif + return manager->tasks; + } + + /* Retrieve new task list */ + array = g_array_new (FALSE, FALSE, sizeof (Task)); + get_task_list (array); + + /* Remove terminated tasks */ + for (i = 0; i < manager->tasks->len; i++) + { + guint j; + Task *task = &g_array_index (manager->tasks, Task, i); + gboolean found = FALSE; + + for (j = 0; j < array->len; j++) + { + Task *tasktmp = &g_array_index (array, Task, j); + if (task->pid != tasktmp->pid) + continue; + found = TRUE; + break; + } + + if (found == FALSE) + g_array_remove_index (manager->tasks, i); + } + + /* Append started tasks and update existing ones */ + for (i = 0; i < array->len; i++) + { + guint j; + Task *tasktmp = &g_array_index (array, Task, i); + gboolean found = FALSE; + + for (j = 0; j < manager->tasks->len; j++) + { + Task *task = &g_array_index (manager->tasks, Task, j); + if (task->pid != tasktmp->pid) + continue; + + found = TRUE; + + task->ppid = tasktmp->ppid; + if (g_strcmp0 (task->state, tasktmp->state)) + g_strlcpy (task->state, tasktmp->state, sizeof (task->state)); + task->cpu_user = tasktmp->cpu_user; + task->cpu_system = tasktmp->cpu_system; + task->rss = tasktmp->rss; + task->vsz = tasktmp->vsz; + task->prio = tasktmp->prio; + break; + } + + if (found == FALSE) + g_array_append_val (manager->tasks, tasktmp); + } + + g_array_free (array, TRUE); + + return manager->tasks; +} + void xtm_task_manager_send_signal_to_pid (XtmTaskManager *manager) { diff --git a/src/task-manager.h b/src/task-manager.h index b1b05bd..76eb5eb 100644 --- a/src/task-manager.h +++ b/src/task-manager.h @@ -23,17 +23,18 @@ typedef struct _Task Task; struct _Task { - guint uid; - gchar uid_name[64]; - guint pid; - guint ppid; - gchar program_name[64]; - gchar full_cmdline[255]; - gchar state[16]; - gfloat cpu; - guint64 memory_vsz; - guint64 memory_rss; - gushort priority; + guint uid; + gchar uid_name[256]; + guint pid; + guint ppid; + gchar name[256]; + gchar cmdline[1024]; + gchar state[16]; + gfloat cpu_user; + gfloat cpu_system; + guint64 vsz; + guint64 rss; + gshort prio; }; /** @@ -42,7 +43,7 @@ struct _Task gboolean get_memory_usage (guint64 *memory_total, guint64 *memory_free, guint64 *memory_cache, guint64 *memory_buffers, guint64 *swap_total, guint64 *swap_free); gboolean get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system); -//gboolean get_task_list (GArray *task_list); +gboolean get_task_list (GArray *task_list); //void send_signal_to_task (gint task_id, gint signal); //void set_priority_to_task (gint task_id, gint prio); @@ -64,5 +65,6 @@ XtmTaskManager * xtm_task_manager_new (); const gchar * xtm_task_manager_get_username (XtmTaskManager *manager); const gchar * xtm_task_manager_get_hostname (XtmTaskManager *manager); void xtm_task_manager_get_system_info (XtmTaskManager *manager, guint *num_processes, gfloat *cpu, gfloat *memory, gfloat *swap); +const GArray * xtm_task_manager_get_task_list (XtmTaskManager *manager); #endif /* !TASK_MANAGER_H */