blob: 9f8d3c31cac665cb9adc1c41d5413a9788c8f0d2 [file] [log] [blame]
Hisham Muhammadd6231ba2006-03-04 18:16:49 +00001/*
2htop - ProcessList.c
3(C) 2004,2005 Hisham H. Muhammad
4Released under the GNU GPL, see the COPYING file
5in the source distribution for its full text.
6*/
7
Hisham Muhammad2ef18472006-03-13 17:29:18 +00008#ifndef CONFIG_H
9#define CONFIG_H
10#include "config.h"
11#endif
12
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000013#include "ProcessList.h"
14#include "Process.h"
Hisham Muhammada853faa2006-05-30 13:45:40 +000015#include "Vector.h"
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000016#include "UsersTable.h"
17#include "Hashtable.h"
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <unistd.h>
22#include <dirent.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <signal.h>
26#include <stdbool.h>
27#include <sys/utsname.h>
Hisham Muhammad86d63132006-03-24 03:39:04 +000028#include <stdarg.h>
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000029
30#include "debug.h"
31#include <assert.h>
32
33/*{
34#ifndef PROCDIR
35#define PROCDIR "/proc"
36#endif
37
38#ifndef PROCSTATFILE
39#define PROCSTATFILE "/proc/stat"
40#endif
41
42#ifndef PROCMEMINFOFILE
43#define PROCMEMINFOFILE "/proc/meminfo"
44#endif
45
46#ifndef MAX_NAME
Hisham Muhammad86d63132006-03-24 03:39:04 +000047#define MAX_NAME 128
48#endif
49
50#ifndef MAX_READ
51#define MAX_READ 8192
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000052#endif
53
54}*/
55
56/*{
57
58typedef struct ProcessList_ {
Hisham Muhammada853faa2006-05-30 13:45:40 +000059 Vector* processes;
60 Vector* processes2;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +000061 Hashtable* processTable;
62 Process* prototype;
63 UsersTable* usersTable;
64
65 int processorCount;
66 int totalTasks;
67 int runningTasks;
68
69 long int* totalTime;
70 long int* userTime;
71 long int* systemTime;
72 long int* idleTime;
73 long int* niceTime;
74 long int* totalPeriod;
75 long int* userPeriod;
76 long int* systemPeriod;
77 long int* idlePeriod;
78 long int* nicePeriod;
79
80 long int totalMem;
81 long int usedMem;
82 long int freeMem;
83 long int sharedMem;
84 long int buffersMem;
85 long int cachedMem;
86 long int totalSwap;
87 long int usedSwap;
88 long int freeSwap;
89
90 ProcessField* fields;
91 ProcessField sortKey;
92 int direction;
93 bool hideThreads;
94 bool shadowOtherUsers;
95 bool hideKernelThreads;
96 bool hideUserlandThreads;
97 bool treeView;
98 bool highlightBaseName;
99 bool highlightMegabytes;
Hisham Muhammad86d63132006-03-24 03:39:04 +0000100 #ifdef DEBUG
101 FILE* traceFile;
102 #endif
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000103
104} ProcessList;
105}*/
106
107/* private property */
Hisham Muhammad33113fe2006-04-10 20:40:38 +0000108ProcessField defaultHeaders[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000109
Hisham Muhammad86d63132006-03-24 03:39:04 +0000110#ifdef DEBUG
111
112/* private property */
113typedef int(*vxscanf)(void*, const char*, va_list);
114
115#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
116#define ProcessList_fread(this, file, format, ...) ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )
117
118/* private */
119FILE* ProcessList_fopen(ProcessList* this, const char* path, const char* mode) {
120 fprintf(this->traceFile, "[%s]\n", path);
121 return fopen(path, mode);
122}
123
124/* private */
125static inline int ProcessList_xread(ProcessList* this, vxscanf fn, void* buffer, char* format, ...) {
126 va_list ap;
127 va_start(ap, format);
128 int num = fn(buffer, format, ap);
129 va_end(format);
130 va_start(ap, format);
131 while (*format) {
132 char ch = *format;
133 char* c; int* d; long int* ld; unsigned long int* lu; char** s;
134 if (ch != '%') {
135 fprintf(this->traceFile, "%c", ch);
136 format++;
137 continue;
138 }
139 format++;
140 switch(*format) {
141 case 'c': c = va_arg(ap, char*); fprintf(this->traceFile, "%c", *c); break;
142 case 'd': d = va_arg(ap, int*); fprintf(this->traceFile, "%d", *d); break;
143 case 's': s = va_arg(ap, char**); fprintf(this->traceFile, "%s", *s); break;
144 case 'l':
145 format++;
146 switch (*format) {
147 case 'd': ld = va_arg(ap, long int*); fprintf(this->traceFile, "%ld", *ld); break;
148 case 'u': lu = va_arg(ap, unsigned long int*); fprintf(this->traceFile, "%lu", *lu); break;
149 }
150 }
151 format++;
152 }
153 fprintf(this->traceFile, "\n");
154 va_end(format);
155 return num;
156}
157
158#else
159
160#ifndef ProcessList_read
161#define ProcessList_fopen(this, path, mode) fopen(path, mode)
162#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
163#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
164#endif
165
166#endif
167
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000168ProcessList* ProcessList_new(UsersTable* usersTable) {
169 ProcessList* this;
170 this = malloc(sizeof(ProcessList));
Hisham Muhammada853faa2006-05-30 13:45:40 +0000171 this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000172 this->processTable = Hashtable_new(20, false);
173 this->prototype = Process_new(this);
174 this->usersTable = usersTable;
175
176 /* tree-view auxiliary buffers */
Hisham Muhammada853faa2006-05-30 13:45:40 +0000177 this->processes2 = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000178
179 #ifdef DEBUG
180 this->traceFile = fopen("/tmp/htop-proc-trace", "w");
181 #endif
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000182
183 FILE* status = fopen(PROCSTATFILE, "r");
184 assert(status != NULL);
185 char buffer[256];
186 int procs = -1;
187 do {
188 procs++;
189 fgets(buffer, 255, status);
190 } while (String_startsWith(buffer, "cpu"));
191 fclose(status);
192 this->processorCount = procs - 1;
193 this->totalTime = calloc(procs, sizeof(long int));
194 this->userTime = calloc(procs, sizeof(long int));
195 this->systemTime = calloc(procs, sizeof(long int));
196 this->niceTime = calloc(procs, sizeof(long int));
197 this->idleTime = calloc(procs, sizeof(long int));
198 this->totalPeriod = calloc(procs, sizeof(long int));
199 this->userPeriod = calloc(procs, sizeof(long int));
200 this->systemPeriod = calloc(procs, sizeof(long int));
201 this->nicePeriod = calloc(procs, sizeof(long int));
202 this->idlePeriod = calloc(procs, sizeof(long int));
203 for (int i = 0; i < procs; i++) {
204 this->totalTime[i] = 1;
205 this->totalPeriod[i] = 1;
206 }
207
208 this->fields = calloc(sizeof(ProcessField), LAST_PROCESSFIELD+1);
Hisham Muhammada853faa2006-05-30 13:45:40 +0000209 // TODO: turn 'fields' into a Vector,
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000210 // (and ProcessFields into proper objects).
211 for (int i = 0; defaultHeaders[i]; i++) {
212 this->fields[i] = defaultHeaders[i];
213 }
214 this->sortKey = PERCENT_CPU;
215 this->direction = 1;
216 this->hideThreads = false;
217 this->shadowOtherUsers = false;
218 this->hideKernelThreads = false;
219 this->hideUserlandThreads = false;
220 this->treeView = false;
221 this->highlightBaseName = false;
222 this->highlightMegabytes = false;
223
224 return this;
225}
226
227void ProcessList_delete(ProcessList* this) {
228 Hashtable_delete(this->processTable);
Hisham Muhammada853faa2006-05-30 13:45:40 +0000229 Vector_delete(this->processes);
230 Vector_delete(this->processes2);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000231 Process_delete((Object*)this->prototype);
232
233 free(this->totalTime);
234 free(this->userTime);
235 free(this->systemTime);
236 free(this->niceTime);
237 free(this->idleTime);
238 free(this->totalPeriod);
239 free(this->userPeriod);
240 free(this->systemPeriod);
241 free(this->nicePeriod);
242 free(this->idlePeriod);
243
Hisham Muhammad86d63132006-03-24 03:39:04 +0000244 #ifdef DEBUG
245 fclose(this->traceFile);
246 #endif
247
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000248 free(this->fields);
249 free(this);
250}
251
252void ProcessList_invertSortOrder(ProcessList* this) {
253 if (this->direction == 1)
254 this->direction = -1;
255 else
256 this->direction = 1;
257}
258
259RichString ProcessList_printHeader(ProcessList* this) {
260 RichString out = RichString_new();
261 ProcessField* fields = this->fields;
262 for (int i = 0; fields[i]; i++) {
263 char* field = Process_printField(fields[i]);
264 if (this->sortKey == fields[i])
265 RichString_append(&out, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
266 else
267 RichString_append(&out, CRT_colors[PANEL_HEADER_FOCUS], field);
268 }
269 return out;
270}
271
272
273void ProcessList_prune(ProcessList* this) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000274 Vector_prune(this->processes);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000275}
276
277void ProcessList_add(ProcessList* this, Process* p) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000278 Vector_add(this->processes, p);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000279 Hashtable_put(this->processTable, p->pid, p);
280}
281
282void ProcessList_remove(ProcessList* this, Process* p) {
283 Hashtable_remove(this->processTable, p->pid);
284 ProcessField pf = this->sortKey;
285 this->sortKey = PID;
Hisham Muhammada853faa2006-05-30 13:45:40 +0000286 int index = Vector_indexOf(this->processes, p);
287 Vector_remove(this->processes, index);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000288 this->sortKey = pf;
289}
290
291Process* ProcessList_get(ProcessList* this, int index) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000292 return (Process*) (Vector_get(this->processes, index));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000293}
294
295int ProcessList_size(ProcessList* this) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000296 return (Vector_size(this->processes));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000297}
298
299/* private */
300void ProcessList_buildTree(ProcessList* this, int pid, int level, int indent, int direction) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000301 Vector* children = Vector_new(PROCESS_CLASS, false, DEFAULT_SIZE);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000302
Hisham Muhammada853faa2006-05-30 13:45:40 +0000303 for (int i = 0; i < Vector_size(this->processes); i++) {
304 Process* process = (Process*) (Vector_get(this->processes, i));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000305 if (process->ppid == pid) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000306 Process* process = (Process*) (Vector_take(this->processes, i));
307 Vector_add(children, process);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000308 i--;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000309 }
310 }
Hisham Muhammada853faa2006-05-30 13:45:40 +0000311 int size = Vector_size(children);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000312 for (int i = 0; i < size; i++) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000313 Process* process = (Process*) (Vector_get(children, i));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000314 if (direction == 1)
Hisham Muhammada853faa2006-05-30 13:45:40 +0000315 Vector_add(this->processes2, process);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000316 else
Hisham Muhammada853faa2006-05-30 13:45:40 +0000317 Vector_insert(this->processes2, 0, process);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000318 int nextIndent = indent;
319 if (i < size - 1)
320 nextIndent = indent | (1 << level);
321 ProcessList_buildTree(this, process->pid, level+1, nextIndent, direction);
322 process->indent = indent | (1 << level);
323 }
Hisham Muhammada853faa2006-05-30 13:45:40 +0000324 Vector_delete(children);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000325}
326
327void ProcessList_sort(ProcessList* this) {
328 if (!this->treeView) {
Hisham Muhammada853faa2006-05-30 13:45:40 +0000329 Vector_sort(this->processes);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000330 } else {
331 int direction = this->direction;
332 int sortKey = this->sortKey;
333 this->sortKey = PID;
334 this->direction = 1;
Hisham Muhammada853faa2006-05-30 13:45:40 +0000335 Vector_sort(this->processes);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000336 this->sortKey = sortKey;
337 this->direction = direction;
Hisham Muhammada853faa2006-05-30 13:45:40 +0000338 Process* init = (Process*) (Vector_take(this->processes, 0));
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000339 assert(init->pid == 1);
340 init->indent = 0;
Hisham Muhammada853faa2006-05-30 13:45:40 +0000341 Vector_add(this->processes2, init);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000342 ProcessList_buildTree(this, init->pid, 0, 0, direction);
Hisham Muhammada853faa2006-05-30 13:45:40 +0000343 Vector* t = this->processes;
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000344 this->processes = this->processes2;
345 this->processes2 = t;
346 }
347}
348
349/* private */
Hisham Muhammad86d63132006-03-24 03:39:04 +0000350int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, char *command) {
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000351 static char buf[MAX_READ];
352 long int zero;
353
354 int size = fread(buf, 1, MAX_READ, f);
355 if(!size) return 0;
356
357 proc->pid = atoi(buf);
358 char *location = strchr(buf, ' ');
359 if(!location) return 0;
360
361 location += 2;
362 char *end = strrchr(location, ')');
363 if(!end) return 0;
364
365 int commsize = end - location;
366 memcpy(command, location, commsize);
367 command[commsize] = '\0';
368 location = end + 2;
369
Hisham Muhammad86d63132006-03-24 03:39:04 +0000370 int num = ProcessList_read(this, location,
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000371 "%c %d %d %d %d %d %lu %lu %lu %lu "
372 "%lu %lu %lu %ld %ld %ld %ld %ld %ld "
373 "%lu %lu %ld %lu %lu %lu %lu %lu "
374 "%lu %lu %lu %lu %lu %lu %lu %lu "
375 "%d %d",
376 &proc->state, &proc->ppid, &proc->pgrp, &proc->session, &proc->tty_nr,
377 &proc->tpgid, &proc->flags, &proc->minflt, &proc->cminflt, &proc->majflt,
378 &proc->cmajflt, &proc->utime, &proc->stime, &proc->cutime, &proc->cstime,
379 &proc->priority, &proc->nice, &zero, &proc->itrealvalue,
380 &proc->starttime, &proc->vsize, &proc->rss, &proc->rlim,
381 &proc->startcode, &proc->endcode, &proc->startstack, &proc->kstkesp,
382 &proc->kstkeip, &proc->signal, &proc->blocked, &proc->sigignore,
383 &proc->sigcatch, &proc->wchan, &proc->nswap, &proc->cnswap,
384 &proc->exit_signal, &proc->processor);
385
386 // This assert is always valid on 2.4, but reportedly not always valid on 2.6.
387 // TODO: Check if the semantics of this field has changed.
388 // assert(zero == 0);
389
390 if(num != 37) return 0;
391 return 1;
392}
393
Hisham Muhammad86d63132006-03-24 03:39:04 +0000394bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name) {
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000395 char statusfilename[MAX_NAME+1];
396 statusfilename[MAX_NAME] = '\0';
397 snprintf(statusfilename, MAX_NAME, "%s/%s/status", dirname, name);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000398 FILE* status = ProcessList_fopen(this, statusfilename, "r");
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000399 bool success = false;
400 if (status) {
401 char buffer[1024];
402 buffer[1023] = '\0';
403 while (!feof(status)) {
404 char* ok = fgets(buffer, 1023, status);
405 if (!ok)
406 break;
407 if (String_startsWith(buffer, "Uid:")) {
408 int uid1, uid2, uid3, uid4;
409 // TODO: handle other uid's.
Hisham Muhammad86d63132006-03-24 03:39:04 +0000410 int ok = ProcessList_read(this, buffer, "Uid:\t%d\t%d\t%d\t%d", &uid1, &uid2, &uid3, &uid4);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000411 if (ok >= 1) {
412 proc->st_uid = uid1;
413 success = true;
414 }
415 break;
416 }
417 }
418 fclose(status);
419 }
420 if (!success) {
421 snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name);
422 struct stat sstat;
423 int statok = stat(statusfilename, &sstat);
424 if (statok == -1)
425 return false;
426 proc->st_uid = sstat.st_uid;
427 }
428 return success;
429}
430
431void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, float period) {
432 DIR* dir;
433 struct dirent* entry;
434 Process* prototype = this->prototype;
435
436 dir = opendir(dirname);
437 assert(dir != NULL);
438 while ((entry = readdir(dir)) != NULL) {
439 char* name = entry->d_name;
440 int pid;
441 // filename is a number: process directory
442 pid = atoi(name);
443
444 // The RedHat kernel hides threads with a dot.
445 // I believe this is non-standard.
446 bool isThread = false;
447 if ((!this->hideThreads) && pid == 0 && name[0] == '.') {
448 char* tname = name + 1;
449 pid = atoi(tname);
450 if (pid > 0)
451 isThread = true;
452 }
453
454 if (pid > 0 && pid != parent) {
455 if (!this->hideUserlandThreads) {
456 char subdirname[MAX_NAME+1];
457 snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
458
459 if (access(subdirname, X_OK) == 0) {
460 ProcessList_processEntries(this, subdirname, pid, period);
461 }
Hisham Muhammad86d63132006-03-24 03:39:04 +0000462 }
463
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000464 FILE* status;
465 char statusfilename[MAX_NAME+1];
466 char command[PROCESS_COMM_LEN + 1];
467
468 Process* process;
469 Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid);
470 if (!existingProcess) {
471 process = Process_clone(prototype);
472 process->pid = pid;
473 ProcessList_add(this, process);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000474 if (! ProcessList_readStatusFile(this, process, dirname, name))
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000475 goto errorReadingProcess;
476 } else {
477 process = existingProcess;
478 }
479 process->updated = true;
480
481 char* username = UsersTable_getRef(this->usersTable, process->st_uid);
482 if (username) {
483 strncpy(process->user, username, PROCESS_USER_LEN);
484 } else {
485 snprintf(process->user, PROCESS_USER_LEN, "%d", process->st_uid);
486 }
487
488 int lasttimes = (process->utime + process->stime);
489
490 snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000491
492 status = ProcessList_fopen(this, statusfilename, "r");
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000493 if (status == NULL)
494 goto errorReadingProcess;
Hisham Muhammad86d63132006-03-24 03:39:04 +0000495
496 int success = ProcessList_readStatFile(this, process, status, command);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000497 fclose(status);
498 if(!success) {
499 goto errorReadingProcess;
500 }
501
502 process->percent_cpu = (process->utime + process->stime - lasttimes) /
503 period * 100.0;
504
505 if(!existingProcess) {
506 snprintf(statusfilename, MAX_NAME, "%s/%s/cmdline", dirname, name);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000507 status = ProcessList_fopen(this, statusfilename, "r");
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000508 if (!status) {
509 goto errorReadingProcess;
510 }
511
512 int amtRead = fread(command, 1, PROCESS_COMM_LEN - 1, status);
513 if (amtRead > 0) {
514 for (int i = 0; i < amtRead; i++)
515 if (command[i] == '\0' || command[i] == '\n')
516 command[i] = ' ';
517 command[amtRead] = '\0';
518 }
519 command[PROCESS_COMM_LEN] = '\0';
520 process->comm = String_copy(command);
521 fclose(status);
522 }
523
524 snprintf(statusfilename, MAX_NAME, "%s/%s/statm", dirname, name);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000525 status = ProcessList_fopen(this, statusfilename, "r");
526
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000527 if(!status) {
528 goto errorReadingProcess;
529 }
Hisham Muhammad86d63132006-03-24 03:39:04 +0000530 int num = ProcessList_fread(this, status, "%d %d %d %d %d %d %d",
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000531 &process->m_size, &process->m_resident, &process->m_share,
532 &process->m_trs, &process->m_drs, &process->m_lrs,
533 &process->m_dt);
Hisham Muhammad86d63132006-03-24 03:39:04 +0000534
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000535 fclose(status);
536 if(num != 7)
537 goto errorReadingProcess;
538
539 process->percent_mem = process->m_resident /
540 (float)(this->usedMem - this->cachedMem - this->buffersMem) *
541 100.0;
542
543 this->totalTasks++;
Hisham Muhammad86d63132006-03-24 03:39:04 +0000544 if (process->state == 'R') {
545 this->runningTasks++;
546 }
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000547
548 if (this->hideKernelThreads && process->m_size == 0)
549 ProcessList_remove(this, process);
550
551 continue;
552
553 // Exception handler.
554 errorReadingProcess: {
555 ProcessList_remove(this, process);
556 }
557 }
558 }
559 closedir(dir);
560}
561
562void ProcessList_scan(ProcessList* this) {
563 long int usertime, nicetime, systemtime, idletime, totaltime;
564 long int swapFree;
565
566 FILE* status;
567 char buffer[128];
Hisham Muhammad86d63132006-03-24 03:39:04 +0000568 status = ProcessList_fopen(this, PROCMEMINFOFILE, "r");
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000569 assert(status != NULL);
570 while (!feof(status)) {
571 fgets(buffer, 128, status);
572
573 switch (buffer[0]) {
574 case 'M':
575 if (String_startsWith(buffer, "MemTotal:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000576 ProcessList_read(this, buffer, "MemTotal: %ld kB", &this->totalMem);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000577 else if (String_startsWith(buffer, "MemFree:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000578 ProcessList_read(this, buffer, "MemFree: %ld kB", &this->freeMem);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000579 else if (String_startsWith(buffer, "MemShared:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000580 ProcessList_read(this, buffer, "MemShared: %ld kB", &this->sharedMem);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000581 break;
582 case 'B':
583 if (String_startsWith(buffer, "Buffers:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000584 ProcessList_read(this, buffer, "Buffers: %ld kB", &this->buffersMem);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000585 break;
586 case 'C':
587 if (String_startsWith(buffer, "Cached:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000588 ProcessList_read(this, buffer, "Cached: %ld kB", &this->cachedMem);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000589 break;
590 case 'S':
591 if (String_startsWith(buffer, "SwapTotal:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000592 ProcessList_read(this, buffer, "SwapTotal: %ld kB", &this->totalSwap);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000593 if (String_startsWith(buffer, "SwapFree:"))
Hisham Muhammad86d63132006-03-24 03:39:04 +0000594 ProcessList_read(this, buffer, "SwapFree: %ld kB", &swapFree);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000595 break;
596 }
597 }
Hisham Muhammad86d63132006-03-24 03:39:04 +0000598
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000599 this->usedMem = this->totalMem - this->freeMem;
600 this->usedSwap = this->totalSwap - swapFree;
601 fclose(status);
602
Hisham Muhammad86d63132006-03-24 03:39:04 +0000603 status = ProcessList_fopen(this, PROCSTATFILE, "r");
604
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000605 assert(status != NULL);
606 for (int i = 0; i <= this->processorCount; i++) {
607 char buffer[256];
608 int cpuid;
609 long int ioWait, irq, softIrq, steal;
610 ioWait = irq = softIrq = steal = 0;
611 // Dependending on your kernel version,
612 // 5, 7 or 8 of these fields will be set.
613 // The rest will remain at zero.
614 fgets(buffer, 255, status);
615 if (i == 0)
Hisham Muhammad86d63132006-03-24 03:39:04 +0000616 ProcessList_read(this, buffer, "cpu %ld %ld %ld %ld %ld %ld %ld %ld", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000617 else {
Hisham Muhammad86d63132006-03-24 03:39:04 +0000618 ProcessList_read(this, buffer, "cpu%d %ld %ld %ld %ld %ld %ld %ld %ld", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000619 assert(cpuid == i - 1);
620 }
621 // Fields existing on kernels >= 2.6
622 // (and RHEL's patched kernel 2.4...)
623 systemtime += ioWait + irq + softIrq + steal;
624 totaltime = usertime + nicetime + systemtime + idletime;
625 assert (usertime >= this->userTime[i]);
626 assert (nicetime >= this->niceTime[i]);
627 assert (systemtime >= this->systemTime[i]);
628 assert (idletime >= this->idleTime[i]);
629 assert (totaltime >= this->totalTime[i]);
630 this->userPeriod[i] = usertime - this->userTime[i];
631 this->nicePeriod[i] = nicetime - this->niceTime[i];
632 this->systemPeriod[i] = systemtime - this->systemTime[i];
633 this->idlePeriod[i] = idletime - this->idleTime[i];
634 this->totalPeriod[i] = totaltime - this->totalTime[i];
635 this->userTime[i] = usertime;
636 this->niceTime[i] = nicetime;
637 this->systemTime[i] = systemtime;
638 this->idleTime[i] = idletime;
639 this->totalTime[i] = totaltime;
640 }
641 float period = (float)this->totalPeriod[0] / this->processorCount;
642 fclose(status);
643
644 // mark all process as "dirty"
Hisham Muhammada853faa2006-05-30 13:45:40 +0000645 for (int i = 0; i < Vector_size(this->processes); i++) {
646 Process* p = (Process*) Vector_get(this->processes, i);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000647 p->updated = false;
648 }
649
650 this->totalTasks = 0;
651 this->runningTasks = 0;
652
653 signal(11, ProcessList_dontCrash);
654
655 ProcessList_processEntries(this, PROCDIR, 0, period);
656 signal(11, SIG_DFL);
657
Hisham Muhammada853faa2006-05-30 13:45:40 +0000658 for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
659 Process* p = (Process*) Vector_get(this->processes, i);
Hisham Muhammadd6231ba2006-03-04 18:16:49 +0000660 if (p->updated == false)
661 ProcessList_remove(this, p);
662 else
663 p->updated = false;
664 }
665
666}
667
668void ProcessList_dontCrash(int signal) {
669 // This ugly hack was added because I suspect some
670 // crashes were caused by contents of /proc vanishing
671 // away while we read them.
672}