ProcessList.c 25.5 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
3
4
5
6
7
/*
htop - ProcessList.c
(C) 2004,2005 Hisham H. Muhammad
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

8
9
10
11
12
#ifndef CONFIG_H
#define CONFIG_H
#include "config.h"
#endif

Hisham Muhammad's avatar
Hisham Muhammad committed
13
14
#include "ProcessList.h"
#include "Process.h"
15
#include "Vector.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
16
17
#include "UsersTable.h"
#include "Hashtable.h"
18
#include "String.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
19
20
21
22
23
24
25
26
27
28

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/utsname.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
29
#include <stdarg.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
30
31
32
33
34
35
36
37
38
39

#include "debug.h"
#include <assert.h>

/*{
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif

#ifndef PROCSTATFILE
40
#define PROCSTATFILE PROCDIR "/stat"
Hisham Muhammad's avatar
Hisham Muhammad committed
41
42
43
#endif

#ifndef PROCMEMINFOFILE
44
#define PROCMEMINFOFILE PROCDIR "/meminfo"
Hisham Muhammad's avatar
Hisham Muhammad committed
45
46
47
#endif

#ifndef MAX_NAME
Hisham Muhammad's avatar
Hisham Muhammad committed
48
49
50
51
#define MAX_NAME 128
#endif

#ifndef MAX_READ
52
#define MAX_READ 2048
Hisham Muhammad's avatar
Hisham Muhammad committed
53
54
#endif

55
#ifndef PER_PROCESSOR_FIELDS
56
#define PER_PROCESSOR_FIELDS 22
57
58
#endif

Hisham Muhammad's avatar
Hisham Muhammad committed
59
60
61
62
}*/

/*{

63
#ifdef DEBUG_PROC
64
65
66
typedef int(*vxscanf)(void*, const char*, va_list);
#endif

Hisham Muhammad's avatar
Hisham Muhammad committed
67
typedef struct ProcessList_ {
68
69
   Vector* processes;
   Vector* processes2;
Hisham Muhammad's avatar
Hisham Muhammad committed
70
71
72
73
74
75
76
77
   Hashtable* processTable;
   Process* prototype;
   UsersTable* usersTable;

   int processorCount;
   int totalTasks;
   int runningTasks;

78
   // Must match number of PER_PROCESSOR_FIELDS constant
79
80
81
   unsigned long long int* totalTime;
   unsigned long long int* userTime;
   unsigned long long int* systemTime;
82
   unsigned long long int* systemAllTime;
83
   unsigned long long int* idleAllTime;
84
85
   unsigned long long int* idleTime;
   unsigned long long int* niceTime;
86
87
88
89
   unsigned long long int* ioWaitTime;
   unsigned long long int* irqTime;
   unsigned long long int* softIrqTime;
   unsigned long long int* stealTime;
90
91
92
   unsigned long long int* totalPeriod;
   unsigned long long int* userPeriod;
   unsigned long long int* systemPeriod;
93
   unsigned long long int* systemAllPeriod;
94
   unsigned long long int* idleAllPeriod;
95
96
   unsigned long long int* idlePeriod;
   unsigned long long int* nicePeriod;
97
98
99
100
   unsigned long long int* ioWaitPeriod;
   unsigned long long int* irqPeriod;
   unsigned long long int* softIrqPeriod;
   unsigned long long int* stealPeriod;
101
102
103
104
105
106
107
108
109
110

   unsigned long long int totalMem;
   unsigned long long int usedMem;
   unsigned long long int freeMem;
   unsigned long long int sharedMem;
   unsigned long long int buffersMem;
   unsigned long long int cachedMem;
   unsigned long long int totalSwap;
   unsigned long long int usedSwap;
   unsigned long long int freeSwap;
Hisham Muhammad's avatar
Hisham Muhammad committed
111
112
113
114
115
116
117
118
119
120
121

   ProcessField* fields;
   ProcessField sortKey;
   int direction;
   bool hideThreads;
   bool shadowOtherUsers;
   bool hideKernelThreads;
   bool hideUserlandThreads;
   bool treeView;
   bool highlightBaseName;
   bool highlightMegabytes;
122
   bool detailedCPUTime;
123
   #ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
124
125
   FILE* traceFile;
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
126
127
128
129

} ProcessList;
}*/

130
static ProcessField defaultHeaders[] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, 0 };
Hisham Muhammad's avatar
Hisham Muhammad committed
131

132
#ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
133
134
135
136

#define ProcessList_read(this, buffer, format, ...) ProcessList_xread(this, (vxscanf) vsscanf, buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...)  ProcessList_xread(this, (vxscanf) vfscanf, file, format, ## __VA_ARGS__ )

137
static FILE* ProcessList_fopen(ProcessList* this, const char* path, const char* mode) {
Hisham Muhammad's avatar
Hisham Muhammad committed
138
139
140
141
142
143
144
145
146
147
148
149
   fprintf(this->traceFile, "[%s]\n", path);
   return fopen(path, mode);
}

static inline int ProcessList_xread(ProcessList* this, vxscanf fn, void* buffer, char* format, ...) {
   va_list ap;
   va_start(ap, format);
   int num = fn(buffer, format, ap);
   va_end(format);
   va_start(ap, format);
   while (*format) {
      char ch = *format;
150
151
152
153
      char* c; int* d;
      long int* ld; unsigned long int* lu;
      long long int* lld; unsigned long long int* llu;
      char** s;
Hisham Muhammad's avatar
Hisham Muhammad committed
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
      if (ch != '%') {
         fprintf(this->traceFile, "%c", ch);
         format++;
         continue;
      }
      format++;
      switch(*format) {
      case 'c': c = va_arg(ap, char*);  fprintf(this->traceFile, "%c", *c); break;
      case 'd': d = va_arg(ap, int*);   fprintf(this->traceFile, "%d", *d); break;
      case 's': s = va_arg(ap, char**); fprintf(this->traceFile, "%s", *s); break;
      case 'l':
         format++;
         switch (*format) {
         case 'd': ld = va_arg(ap, long int*); fprintf(this->traceFile, "%ld", *ld); break;
         case 'u': lu = va_arg(ap, unsigned long int*); fprintf(this->traceFile, "%lu", *lu); break;
169
170
171
172
173
174
         case 'l':
            format++;
            switch (*format) {
            case 'd': lld = va_arg(ap, long long int*); fprintf(this->traceFile, "%lld", *lld); break;
            case 'u': llu = va_arg(ap, unsigned long long int*); fprintf(this->traceFile, "%llu", *llu); break;
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
         }
      }
      format++;
   }
   fprintf(this->traceFile, "\n");
   va_end(format);
   return num;
}

#else

#ifndef ProcessList_read
#define ProcessList_fopen(this, path, mode) fopen(path, mode)
#define ProcessList_read(this, buffer, format, ...) sscanf(buffer, format, ## __VA_ARGS__ )
#define ProcessList_fread(this, file, format, ...) fscanf(file, format, ## __VA_ARGS__ )
#endif

#endif

194
195
196
197
198
199
200
201
202
203
static inline void ProcessList_allocatePerProcessorBuffers(ProcessList* this, int procs) {
   unsigned long long int** bufferPtr = &(this->totalTime);
   unsigned long long int* buffer = calloc(procs * PER_PROCESSOR_FIELDS, sizeof(unsigned long long int));
   for (int i = 0; i < PER_PROCESSOR_FIELDS; i++) {
      *bufferPtr = buffer;
      bufferPtr++;
      buffer += procs;
   }
}

Hisham Muhammad's avatar
Hisham Muhammad committed
204
205
206
ProcessList* ProcessList_new(UsersTable* usersTable) {
   ProcessList* this;
   this = malloc(sizeof(ProcessList));
207
   this->processes = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare);
208
   this->processTable = Hashtable_new(70, false);
209
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
210
211
212
213
   this->prototype = Process_new(this);
   this->usersTable = usersTable;
   
   /* tree-view auxiliary buffers */
214
   this->processes2 = Vector_new(PROCESS_CLASS, true, DEFAULT_SIZE, Process_compare);
Hisham Muhammad's avatar
Hisham Muhammad committed
215
   
216
   #ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
217
218
   this->traceFile = fopen("/tmp/htop-proc-trace", "w");
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
219
220
221
222
223
224
225
226
227
228
229

   FILE* status = fopen(PROCSTATFILE, "r");
   assert(status != NULL);
   char buffer[256];
   int procs = -1;
   do {
      procs++;
      fgets(buffer, 255, status);
   } while (String_startsWith(buffer, "cpu"));
   fclose(status);
   this->processorCount = procs - 1;
230
231
232
   
   ProcessList_allocatePerProcessorBuffers(this, procs);

Hisham Muhammad's avatar
Hisham Muhammad committed
233
234
235
236
237
238
   for (int i = 0; i < procs; i++) {
      this->totalTime[i] = 1;
      this->totalPeriod[i] = 1;
   }

   this->fields = calloc(sizeof(ProcessField), LAST_PROCESSFIELD+1);
239
   // TODO: turn 'fields' into a Vector,
Hisham Muhammad's avatar
Hisham Muhammad committed
240
241
242
243
244
245
246
247
248
249
250
251
252
   // (and ProcessFields into proper objects).
   for (int i = 0; defaultHeaders[i]; i++) {
      this->fields[i] = defaultHeaders[i];
   }
   this->sortKey = PERCENT_CPU;
   this->direction = 1;
   this->hideThreads = false;
   this->shadowOtherUsers = false;
   this->hideKernelThreads = false;
   this->hideUserlandThreads = false;
   this->treeView = false;
   this->highlightBaseName = false;
   this->highlightMegabytes = false;
253
   this->detailedCPUTime = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
254
255
256
257
258
259

   return this;
}

void ProcessList_delete(ProcessList* this) {
   Hashtable_delete(this->processTable);
260
261
   Vector_delete(this->processes);
   Vector_delete(this->processes2);
Hisham Muhammad's avatar
Hisham Muhammad committed
262
263
   Process_delete((Object*)this->prototype);

264
265
   // Free first entry only;
   // other fields are offsets of the same buffer
Hisham Muhammad's avatar
Hisham Muhammad committed
266
267
   free(this->totalTime);

268
   #ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
269
270
271
   fclose(this->traceFile);
   #endif

Hisham Muhammad's avatar
Hisham Muhammad committed
272
273
274
275
276
277
278
279
280
281
282
283
   free(this->fields);
   free(this);
}

void ProcessList_invertSortOrder(ProcessList* this) {
   if (this->direction == 1)
      this->direction = -1;
   else
      this->direction = 1;
}

RichString ProcessList_printHeader(ProcessList* this) {
284
285
   RichString out;
   RichString_init(&out);
Hisham Muhammad's avatar
Hisham Muhammad committed
286
287
288
289
290
291
292
293
294
295
296
297
298
   ProcessField* fields = this->fields;
   for (int i = 0; fields[i]; i++) {
      char* field = Process_printField(fields[i]);
      if (this->sortKey == fields[i])
         RichString_append(&out, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
      else
         RichString_append(&out, CRT_colors[PANEL_HEADER_FOCUS], field);
   }
   return out;
}


void ProcessList_prune(ProcessList* this) {
299
   Vector_prune(this->processes);
Hisham Muhammad's avatar
Hisham Muhammad committed
300
301
302
}

void ProcessList_add(ProcessList* this, Process* p) {
303
304
   assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
   assert(Hashtable_get(this->processTable, p->pid) == NULL);
305
   Vector_add(this->processes, p);
Hisham Muhammad's avatar
Hisham Muhammad committed
306
   Hashtable_put(this->processTable, p->pid, p);
307
308
   assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
   assert(Hashtable_get(this->processTable, p->pid) != NULL);
309
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
310
311
312
}

void ProcessList_remove(ProcessList* this, Process* p) {
313
314
315
   assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
   assert(Hashtable_get(this->processTable, p->pid) != NULL);
   Process* pp = Hashtable_remove(this->processTable, p->pid);
316
   assert(pp == p); (void)pp;
317
   unsigned int pid = p->pid;
318
   int index = Vector_indexOf(this->processes, p, Process_pidCompare);
319
   assert(index != -1);
320
   Vector_remove(this->processes, index);
321
   assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
322
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
323
324
325
}

Process* ProcessList_get(ProcessList* this, int index) {
326
   return (Process*) (Vector_get(this->processes, index));
Hisham Muhammad's avatar
Hisham Muhammad committed
327
328
329
}

int ProcessList_size(ProcessList* this) {
330
   return (Vector_size(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
331
332
}

333
static void ProcessList_buildTree(ProcessList* this, int pid, int level, int indent, int direction) {
334
   Vector* children = Vector_new(PROCESS_CLASS, false, DEFAULT_SIZE, Process_compare);
Hisham Muhammad's avatar
Hisham Muhammad committed
335

336
   for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
337
      Process* process = (Process*) (Vector_get(this->processes, i));
338
      if (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid)) {
339
340
         Process* process = (Process*) (Vector_take(this->processes, i));
         Vector_add(children, process);
Hisham Muhammad's avatar
Hisham Muhammad committed
341
342
      }
   }
343
   int size = Vector_size(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
344
   for (int i = 0; i < size; i++) {
345
      Process* process = (Process*) (Vector_get(children, i));
346
      int s = this->processes2->items;
Hisham Muhammad's avatar
Hisham Muhammad committed
347
      if (direction == 1)
348
         Vector_add(this->processes2, process);
Hisham Muhammad's avatar
Hisham Muhammad committed
349
      else
350
         Vector_insert(this->processes2, 0, process);
351
      assert(this->processes2->items == s+1); (void)s;
Hisham Muhammad's avatar
Hisham Muhammad committed
352
353
354
355
356
357
      int nextIndent = indent;
      if (i < size - 1)
         nextIndent = indent | (1 << level);
      ProcessList_buildTree(this, process->pid, level+1, nextIndent, direction);
      process->indent = indent | (1 << level);
   }
358
   Vector_delete(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
359
360
361
362
}

void ProcessList_sort(ProcessList* this) {
   if (!this->treeView) {
363
      Vector_sort(this->processes);
Hisham Muhammad's avatar
Hisham Muhammad committed
364
   } else {
365
      // Save settings
Hisham Muhammad's avatar
Hisham Muhammad committed
366
367
      int direction = this->direction;
      int sortKey = this->sortKey;
368
      // Sort by PID
Hisham Muhammad's avatar
Hisham Muhammad committed
369
370
      this->sortKey = PID;
      this->direction = 1;
371
      Vector_sort(this->processes);
372
      // Restore settings
Hisham Muhammad's avatar
Hisham Muhammad committed
373
374
      this->sortKey = sortKey;
      this->direction = direction;
375
      // Take PID 1 as root and add to the new listing
376
      int vsize = Vector_size(this->processes);
377
      Process* init = (Process*) (Vector_take(this->processes, 0));
Hisham Muhammad's avatar
Hisham Muhammad committed
378
379
      assert(init->pid == 1);
      init->indent = 0;
380
      Vector_add(this->processes2, init);
381
      // Recursively empty list
Hisham Muhammad's avatar
Hisham Muhammad committed
382
      ProcessList_buildTree(this, init->pid, 0, 0, direction);
383
      // Add leftovers
384
385
386
387
      while (Vector_size(this->processes)) {
         Process* p = (Process*) (Vector_take(this->processes, 0));
         p->indent = 0;
         Vector_add(this->processes2, p);
388
         ProcessList_buildTree(this, p->pid, 0, 0, direction);
389
390
391
      }
      assert(Vector_size(this->processes2) == vsize); (void)vsize;
      assert(Vector_size(this->processes) == 0);
392
      // Swap listings around
393
      Vector* t = this->processes;
Hisham Muhammad's avatar
Hisham Muhammad committed
394
395
396
397
398
      this->processes = this->processes2;
      this->processes2 = t;
   }
}

399
static int ProcessList_readStatFile(ProcessList* this, Process *proc, FILE *f, char *command) {
Hisham Muhammad's avatar
Hisham Muhammad committed
400
   static char buf[MAX_READ];
401
   unsigned long int zero;
Hisham Muhammad's avatar
Hisham Muhammad committed
402
403
404
405

   int size = fread(buf, 1, MAX_READ, f);
   if(!size) return 0;

406
   assert(proc->pid == atoi(buf));
Hisham Muhammad's avatar
Hisham Muhammad committed
407
408
409
410
411
412
413
414
415
416
417
418
   char *location = strchr(buf, ' ');
   if(!location) return 0;

   location += 2;
   char *end = strrchr(location, ')');
   if(!end) return 0;
   
   int commsize = end - location;
   memcpy(command, location, commsize);
   command[commsize] = '\0';
   location = end + 2;
   
419
   #ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
420
   int num = ProcessList_read(this, location, 
421
      "%c %u %u %u %u %d %lu %lu %lu %lu "
Hisham Muhammad's avatar
Hisham Muhammad committed
422
423
424
425
426
      "%lu %lu %lu %ld %ld %ld %ld %ld %ld "
      "%lu %lu %ld %lu %lu %lu %lu %lu "
      "%lu %lu %lu %lu %lu %lu %lu %lu "
      "%d %d",
      &proc->state, &proc->ppid, &proc->pgrp, &proc->session, &proc->tty_nr, 
427
428
429
      &proc->tpgid, &proc->flags,
      &proc->minflt, &proc->cminflt, &proc->majflt, &proc->cmajflt,
      &proc->utime, &proc->stime, &proc->cutime, &proc->cstime, 
430
      &proc->priority, &proc->nice, &proc->nlwp, &proc->itrealvalue,
Hisham Muhammad's avatar
Hisham Muhammad committed
431
432
433
434
435
      &proc->starttime, &proc->vsize, &proc->rss, &proc->rlim, 
      &proc->startcode, &proc->endcode, &proc->startstack, &proc->kstkesp, 
      &proc->kstkeip, &proc->signal, &proc->blocked, &proc->sigignore, 
      &proc->sigcatch, &proc->wchan, &proc->nswap, &proc->cnswap, 
      &proc->exit_signal, &proc->processor);
436
437
438
   #else
   long int uzero;
   int num = ProcessList_read(this, location, 
439
      "%c %u %u %u %u %d %lu %lu %lu %lu "
440
441
442
443
444
445
446
447
      "%lu %lu %lu %ld %ld %ld %ld %ld %ld "
      "%lu %lu %ld %lu %lu %lu %lu %lu "
      "%lu %lu %lu %lu %lu %lu %lu %lu "
      "%d %d",
      &proc->state, &proc->ppid, &proc->pgrp, &proc->session, &proc->tty_nr, 
      &proc->tpgid, &proc->flags,
      &zero, &zero, &zero, &zero,
      &proc->utime, &proc->stime, &proc->cutime, &proc->cstime, 
448
      &proc->priority, &proc->nice, &proc->nlwp, &uzero,
449
450
451
452
453
454
      &zero, &zero, &uzero, &zero, 
      &zero, &zero, &zero, &zero, 
      &zero, &zero, &zero, &zero, 
      &zero, &zero, &zero, &zero, 
      &proc->exit_signal, &proc->processor);
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
455
456
457
458
459
460
461
462
463
   
   // This assert is always valid on 2.4, but reportedly not always valid on 2.6.
   // TODO: Check if the semantics of this field has changed.
   // assert(zero == 0);
   
   if(num != 37) return 0;
   return 1;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
464
bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name) {
Hisham Muhammad's avatar
Hisham Muhammad committed
465
466
   char statusfilename[MAX_NAME+1];
   statusfilename[MAX_NAME] = '\0';
467

468
469
470
   bool success = false;
   char buffer[256];
   buffer[255] = '\0';
471
472
   
   // We need to parse the status file just for tgid, which is missing in stat.
Hisham Muhammad's avatar
Hisham Muhammad committed
473
   snprintf(statusfilename, MAX_NAME, "%s/%s/status", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
474
   FILE* status = ProcessList_fopen(this, statusfilename, "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
475
476
   if (status) {
      while (!feof(status)) {
477
         char* ok = fgets(buffer, 255, status);
Hisham Muhammad's avatar
Hisham Muhammad committed
478
479
         if (!ok)
            break;
480
481
482
         if (String_startsWith(buffer, "Tgid:")) {
            int tgid;
            int ok = ProcessList_read(this, buffer, "Tgid:\t%d", &tgid);
Hisham Muhammad's avatar
Hisham Muhammad committed
483
            if (ok >= 1) {
484
               proc->tgid = tgid;
Hisham Muhammad's avatar
Hisham Muhammad committed
485
486
487
488
489
490
491
               success = true;
            }
            break;
         }
      }
      fclose(status);
   }
492
493
494
495
496
497
498
   snprintf(statusfilename, MAX_NAME, "%s/%s", dirname, name);
   struct stat sstat;
   int statok = stat(statusfilename, &sstat);
   if (statok == -1)
      return false;
   proc->st_uid = sstat.st_uid;
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
499
500
501
502
503
504
505
506
}

void ProcessList_processEntries(ProcessList* this, char* dirname, int parent, float period) {
   DIR* dir;
   struct dirent* entry;
   Process* prototype = this->prototype;

   dir = opendir(dirname);
507
   if (!dir) return;
Hisham Muhammad's avatar
Hisham Muhammad committed
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
   while ((entry = readdir(dir)) != NULL) {
      char* name = entry->d_name;
      int pid;
      // filename is a number: process directory
      pid = atoi(name);

      // The RedHat kernel hides threads with a dot.
      // I believe this is non-standard.
      bool isThread = false;
      if ((!this->hideThreads) && pid == 0 && name[0] == '.') {
         char* tname = name + 1;
         pid = atoi(tname);
         if (pid > 0)
            isThread = true;
      }

      if (pid > 0 && pid != parent) {
         if (!this->hideUserlandThreads) {
            char subdirname[MAX_NAME+1];
            snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
   
529
            ProcessList_processEntries(this, subdirname, pid, period);
Hisham Muhammad's avatar
Hisham Muhammad committed
530
531
         }

Hisham Muhammad's avatar
Hisham Muhammad committed
532
533
534
535
         FILE* status;
         char statusfilename[MAX_NAME+1];
         char command[PROCESS_COMM_LEN + 1];

536
         Process* process = NULL;
537

538
         assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
539
         Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid);
540
         if (existingProcess) {
541
            assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1);
542
            process = existingProcess;
543
            assert(process->pid == pid);
544
545
         } else {
            process = prototype;
546
            assert(process->comm == NULL);
Hisham Muhammad's avatar
Hisham Muhammad committed
547
            process->pid = pid;
Hisham Muhammad's avatar
Hisham Muhammad committed
548
            if (! ProcessList_readStatusFile(this, process, dirname, name))
Hisham Muhammad's avatar
Hisham Muhammad committed
549
550
551
552
               goto errorReadingProcess;
         }
         process->updated = true;

553
554
555
556
557
558
559
560
         snprintf(statusfilename, MAX_NAME, "%s/%s/statm", dirname, name);
         status = ProcessList_fopen(this, statusfilename, "r");

         if(!status) {
            goto errorReadingProcess;
         }
         int num = ProcessList_fread(this, status, "%d %d %d %d %d %d %d",
             &process->m_size, &process->m_resident, &process->m_share, 
561
             &process->m_trs, &process->m_lrs, &process->m_drs, 
562
563
564
565
566
567
568
569
570
             &process->m_dt);

         fclose(status);
         if(num != 7)
            goto errorReadingProcess;

         if (this->hideKernelThreads && process->m_size == 0)
            goto errorReadingProcess;

571
572
573
574
575
576
577
578
579
580
581
582
583
         int lasttimes = (process->utime + process->stime);

         snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name);
         
         status = ProcessList_fopen(this, statusfilename, "r");
         if (status == NULL) 
            goto errorReadingProcess;

         int success = ProcessList_readStatFile(this, process, status, command);
         fclose(status);
         if(!success)
            goto errorReadingProcess;

Hisham Muhammad's avatar
Hisham Muhammad committed
584
         if(!existingProcess) {
585
            process->user = UsersTable_getRef(this->usersTable, process->st_uid);
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607

            #ifdef HAVE_OPENVZ
            if (access("/proc/vz", R_OK) != 0) {
               process->vpid = process->pid;
               process->veid = 0;
            } else {
               snprintf(statusfilename, MAX_NAME, "%s/%s/stat", dirname, name);
               status = ProcessList_fopen(this, statusfilename, "r");
               if (status == NULL) 
                  goto errorReadingProcess;
               num = ProcessList_fread(this, status, 
                  "%*u %*s %*c %*u %*u %*u %*u %*u %*u %*u "
                  "%*u %*u %*u %*u %*u %*u %*u %*u "
                  "%*u %*u %*u %*u %*u %*u %*u %*u "
                  "%*u %*u %*u %*u %*u %*u %*u %*u "
                  "%*u %*u %*u %*u %*u %*u %*u %*u "
                  "%*u %*u %*u %*u %*u %*u %*u "
                  "%u %u",
                  &process->vpid, &process->veid);
               fclose(status);
            }
            #endif
608
 
Hisham Muhammad's avatar
Hisham Muhammad committed
609
            snprintf(statusfilename, MAX_NAME, "%s/%s/cmdline", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
610
            status = ProcessList_fopen(this, statusfilename, "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
            if (!status) {
               goto errorReadingProcess;
            }

            int amtRead = fread(command, 1, PROCESS_COMM_LEN - 1, status);
            if (amtRead > 0) {
               for (int i = 0; i < amtRead; i++)
                  if (command[i] == '\0' || command[i] == '\n')
                     command[i] = ' ';
               command[amtRead] = '\0';
            }
            command[PROCESS_COMM_LEN] = '\0';
            process->comm = String_copy(command);
            fclose(status);
         }

627
628
629
         process->percent_cpu = (process->utime + process->stime - lasttimes) / 
            period * 100.0;

630
631
         process->percent_mem = (process->m_resident * PAGE_SIZE) / 
            (float)(this->totalMem) * 
Hisham Muhammad's avatar
Hisham Muhammad committed
632
633
634
            100.0;

         this->totalTasks++;
Hisham Muhammad's avatar
Hisham Muhammad committed
635
636
637
         if (process->state == 'R') {
            this->runningTasks++;
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
638

639
         if (!existingProcess) {
Hisham Muhammad's avatar
Hisham Muhammad committed
640
            ProcessList_add(this, Process_clone(process));
641
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
642
643
644
645
646

         continue;

         // Exception handler.
         errorReadingProcess: {
647
648
649
650
            if (process->comm) {
               free(process->comm);
               process->comm = NULL;
            }
651
652
            if (existingProcess)
               ProcessList_remove(this, process);
653
            assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
654
655
656
657
658
659
660
         }
      }
   }
   closedir(dir);
}

void ProcessList_scan(ProcessList* this) {
661
   unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime;
662
   unsigned long long int swapFree;
Hisham Muhammad's avatar
Hisham Muhammad committed
663
664
665

   FILE* status;
   char buffer[128];
Hisham Muhammad's avatar
Hisham Muhammad committed
666
   status = ProcessList_fopen(this, PROCMEMINFOFILE, "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
667
668
669
670
671
672
673
   assert(status != NULL);
   while (!feof(status)) {
      fgets(buffer, 128, status);

      switch (buffer[0]) {
      case 'M':
         if (String_startsWith(buffer, "MemTotal:"))
674
            ProcessList_read(this, buffer, "MemTotal: %llu kB", &this->totalMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
675
         else if (String_startsWith(buffer, "MemFree:"))
676
            ProcessList_read(this, buffer, "MemFree: %llu kB", &this->freeMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
677
         else if (String_startsWith(buffer, "MemShared:"))
678
            ProcessList_read(this, buffer, "MemShared: %llu kB", &this->sharedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
679
680
681
         break;
      case 'B':
         if (String_startsWith(buffer, "Buffers:"))
682
            ProcessList_read(this, buffer, "Buffers: %llu kB", &this->buffersMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
683
684
685
         break;
      case 'C':
         if (String_startsWith(buffer, "Cached:"))
686
            ProcessList_read(this, buffer, "Cached: %llu kB", &this->cachedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
687
688
689
         break;
      case 'S':
         if (String_startsWith(buffer, "SwapTotal:"))
690
            ProcessList_read(this, buffer, "SwapTotal: %llu kB", &this->totalSwap);
Hisham Muhammad's avatar
Hisham Muhammad committed
691
         if (String_startsWith(buffer, "SwapFree:"))
692
            ProcessList_read(this, buffer, "SwapFree: %llu kB", &swapFree);
Hisham Muhammad's avatar
Hisham Muhammad committed
693
694
695
         break;
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
696

Hisham Muhammad's avatar
Hisham Muhammad committed
697
698
699
700
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
   fclose(status);

Hisham Muhammad's avatar
Hisham Muhammad committed
701
702
   status = ProcessList_fopen(this, PROCSTATFILE, "r");

Hisham Muhammad's avatar
Hisham Muhammad committed
703
704
705
706
   assert(status != NULL);
   for (int i = 0; i <= this->processorCount; i++) {
      char buffer[256];
      int cpuid;
707
      unsigned long long int ioWait, irq, softIrq, steal;
Hisham Muhammad's avatar
Hisham Muhammad committed
708
709
710
711
712
713
      ioWait = irq = softIrq = steal = 0;
      // Dependending on your kernel version,
      // 5, 7 or 8 of these fields will be set.
      // The rest will remain at zero.
      fgets(buffer, 255, status);
      if (i == 0)
714
         ProcessList_read(this, buffer, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal);
Hisham Muhammad's avatar
Hisham Muhammad committed
715
      else {
716
         ProcessList_read(this, buffer, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal);
Hisham Muhammad's avatar
Hisham Muhammad committed
717
718
719
720
         assert(cpuid == i - 1);
      }
      // Fields existing on kernels >= 2.6
      // (and RHEL's patched kernel 2.4...)
721
722
723
      idlealltime = idletime + ioWait;
      systemalltime = systemtime + irq + softIrq + steal;
      totaltime = usertime + nicetime + systemalltime + idlealltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
724
725
726
727
728
      assert (usertime >= this->userTime[i]);
      assert (nicetime >= this->niceTime[i]);
      assert (systemtime >= this->systemTime[i]);
      assert (idletime >= this->idleTime[i]);
      assert (totaltime >= this->totalTime[i]);
729
      assert (systemalltime >= this->systemAllTime[i]);
730
      assert (idlealltime >= this->idleAllTime[i]);
731
      assert (ioWait >= this->ioWaitTime[i]);
732
733
734
      assert (irq >= this->irqTime[i]);
      assert (softIrq >= this->softIrqTime[i]);
      assert (steal >= this->stealTime[i]);
Hisham Muhammad's avatar
Hisham Muhammad committed
735
736
737
      this->userPeriod[i] = usertime - this->userTime[i];
      this->nicePeriod[i] = nicetime - this->niceTime[i];
      this->systemPeriod[i] = systemtime - this->systemTime[i];
738
      this->systemAllPeriod[i] = systemalltime - this->systemAllTime[i];
739
      this->idleAllPeriod[i] = idlealltime - this->idleAllTime[i];
Hisham Muhammad's avatar
Hisham Muhammad committed
740
      this->idlePeriod[i] = idletime - this->idleTime[i];
741
742
743
744
      this->ioWaitPeriod[i] = ioWait - this->ioWaitTime[i];
      this->irqPeriod[i] = irq - this->irqTime[i];
      this->softIrqPeriod[i] = softIrq - this->softIrqTime[i];
      this->stealPeriod[i] = steal - this->stealTime[i];
Hisham Muhammad's avatar
Hisham Muhammad committed
745
746
747
748
      this->totalPeriod[i] = totaltime - this->totalTime[i];
      this->userTime[i] = usertime;
      this->niceTime[i] = nicetime;
      this->systemTime[i] = systemtime;
749
      this->systemAllTime[i] = systemalltime;
750
      this->idleAllTime[i] = idlealltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
751
      this->idleTime[i] = idletime;
752
753
754
755
      this->ioWaitTime[i] = ioWait;
      this->irqTime[i] = irq;
      this->softIrqTime[i] = softIrq;
      this->stealTime[i] = steal;
Hisham Muhammad's avatar
Hisham Muhammad committed
756
757
758
759
760
761
      this->totalTime[i] = totaltime;
   }
   float period = (float)this->totalPeriod[0] / this->processorCount;
   fclose(status);

   // mark all process as "dirty"
762
763
   for (int i = 0; i < Vector_size(this->processes); i++) {
      Process* p = (Process*) Vector_get(this->processes, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
764
765
766
767
768
769
770
771
      p->updated = false;
   }
   
   this->totalTasks = 0;
   this->runningTasks = 0;
   
   ProcessList_processEntries(this, PROCDIR, 0, period);
   
772
773
   for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
      Process* p = (Process*) Vector_get(this->processes, i);
Hisham Muhammad's avatar
Hisham Muhammad committed
774
775
776
777
778
779
780
      if (p->updated == false)
         ProcessList_remove(this, p);
      else
         p->updated = false;
   }

}