Files
xfce4-taskmanager/src/task-manager-linux.c
2010-05-21 15:29:45 +02:00

342 lines
8.6 KiB
C

/*
* Copyright (c) 2008-2010 Mike Massonnet <mmassonnet@xfce.org>
* Copyright (c) 2006 Johannes Zellner <webmaster@nebulon.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <unistd.h>
#include <string.h>
#include <glib.h>
#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)
{
FILE *file;
gchar buffer[1024];
gchar *filename = "/proc/meminfo";
gushort found = 0;
if ((file = fopen (filename, "r")) == NULL)
return FALSE;
while (found < 6 && fgets (buffer, 1024, file) != NULL)
{
found += sscanf (buffer, "MemTotal:\t%u kB", memory_total);
found += sscanf (buffer, "MemFree:\t%u kB", memory_free);
found += sscanf (buffer, "Cached:\t%u kB", memory_cache);
found += sscanf (buffer, "Buffers:\t%u kB", memory_buffers);
found += sscanf (buffer, "SwapTotal:\t%u kB", swap_total);
found += sscanf (buffer, "SwapFree:\t%u kB", swap_free);
}
fclose (file);
*memory_total *= 1024;
*memory_free *= 1024;
*memory_cache *= 1024;
*memory_buffers *= 1024;
*swap_total *= 1024;
*swap_free *= 1024;
return TRUE;
}
gboolean
get_cpu_usage (gushort *cpu_count, gfloat *cpu_user, gfloat *cpu_system)
{
FILE *file;
gchar *filename = "/proc/stat";
gchar buffer[1024];
static gulong cur_jiffies_user = 0, old_jiffies_user = 0;
static gulong cur_jiffies_system = 0, old_jiffies_system = 0;
static gulong cur_jiffies = 0, old_jiffies = 0;
gulong user, user_nice, system, idle;
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);
if (_cpu_count == 0)
{
_cpu_count = 0;
while (fgets (buffer, 1024, file) != NULL)
{
if (buffer[0] != 'c' && buffer[1] != 'p' && buffer[2] != 'u')
break;
_cpu_count += 1;
}
if (_cpu_count == 0)
_cpu_count += 1;
}
fclose (file);
old_jiffies_user = cur_jiffies_user;
old_jiffies_system = cur_jiffies_system;
old_jiffies = cur_jiffies;
cur_jiffies_user = user + user_nice;
cur_jiffies_system = system;
cur_jiffies = cur_jiffies_user + cur_jiffies_system + idle;
*cpu_user = *cpu_system = 0.0;
if (cur_jiffies > old_jiffies)
{
*cpu_user = (cur_jiffies_user - old_jiffies_user) * 100 / (gdouble)(cur_jiffies - old_jiffies);
*cpu_system = (cur_jiffies_system - old_jiffies_system) * 100 / (gdouble)(cur_jiffies - old_jiffies);
}
*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 gboolean
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 FALSE;
/* Read full command byte per byte until EOF */
for (i = 0; (c = fgetc (file)) != EOF && i < sizeof (task->cmdline) - 1; i++)
task->cmdline[i] = (c == '\0') ? ' ' : c;
task->cmdline[i] = '\0';
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';
}
return TRUE;
}
static void
get_cpu_percent (guint pid, gulong jiffies_user, gfloat *cpu_user, gulong jiffies_system, gfloat *cpu_system)
{
static GHashTable *hash_cpu_user = NULL;
static GHashTable *hash_cpu_system = NULL;
gulong jiffies_user_old, jiffies_system_old;
if (hash_cpu_user == NULL)
{
hash_cpu_user = g_hash_table_new (NULL, NULL);
hash_cpu_system = g_hash_table_new (NULL, NULL);
}
jiffies_user_old = GPOINTER_TO_UINT (g_hash_table_lookup (hash_cpu_user, GUINT_TO_POINTER (pid)));
jiffies_system_old = GPOINTER_TO_UINT (g_hash_table_lookup (hash_cpu_system, GUINT_TO_POINTER (pid)));
g_hash_table_insert (hash_cpu_user, GUINT_TO_POINTER (pid), GUINT_TO_POINTER (jiffies_user));
g_hash_table_insert (hash_cpu_system, GUINT_TO_POINTER (pid), GUINT_TO_POINTER (jiffies_system));
if (jiffies_user < jiffies_user_old || jiffies_system < jiffies_system_old)
return;
if (_cpu_count > 0)
{
*cpu_user = (jiffies_user_old > 0) ? (jiffies_user - jiffies_user_old) / (gfloat)_cpu_count : 0;
*cpu_system = (jiffies_system_old > 0) ? (jiffies_system - jiffies_system_old) / (gfloat)_cpu_count : 0;
}
else
{
*cpu_user = *cpu_system = 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);
/* Scanning the short process name is unreliable with scanf when it contains
* spaces, retrieve it manually and fill the buffer */
{
gchar *p1, *po, *p2;
guint i = 0;
p1 = po = g_strstr_len (buffer, -1, "(");
p2 = g_strrstr (buffer, ")");
while (po <= p2)
{
if (po > p1 && po < p2)
{
task->name[i++] = *po;
task->name[i] = '\0';
}
*po = 'x';
po++;
}
}
/* Parse the stat file */
{
gchar dummy[256];
gint idummy;
gulong jiffies_user, jiffies_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
dummy, // 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
&jiffies_user, // utime the number of jiffies that this process has scheduled in user mode
&jiffies_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 ();
get_cpu_percent (task->pid, jiffies_user, &task->cpu_user, jiffies_system, &task->cpu_system);
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));
}
/* Read the full command line */
if (!get_task_cmdline (task))
return FALSE;
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;
}
gboolean
pid_is_sleeping (guint pid)
{
FILE *file;
gchar filename[96];
gchar buffer[1024];
gchar state[2];
snprintf (filename, 96, "/proc/%i/status", pid);
if ((file = fopen (filename, "r")) == NULL)
return FALSE;
while (fgets (buffer, 1024, file) != NULL)
{
if (sscanf (buffer, "State:\t%1s", state) > 0)
break;
}
fclose (file);
return (state[0] == 'T') ? TRUE : FALSE;
}