ProcessList.c 25.9 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 highlightThreads;
123
   bool detailedCPUTime;
124
   #ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
125
126
   FILE* traceFile;
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
127
128
129
130

} ProcessList;
}*/

131
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
132

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

#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__ )

138
static FILE* ProcessList_fopen(ProcessList* this, const char* path, const char* mode) {
Hisham Muhammad's avatar
Hisham Muhammad committed
139
140
141
142
143
144
145
146
147
148
149
150
   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;
151
152
153
154
      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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
      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;
170
171
172
173
174
175
         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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
         }
      }
      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

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

   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;
231
232
233
   
   ProcessList_allocatePerProcessorBuffers(this, procs);

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

   this->fields = calloc(sizeof(ProcessField), LAST_PROCESSFIELD+1);
240
   // TODO: turn 'fields' into a Vector,
Hisham Muhammad's avatar
Hisham Muhammad committed
241
242
243
244
245
246
247
248
249
250
251
252
253
   // (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;
254
   this->detailedCPUTime = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
255
256
257
258
259
260

   return this;
}

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
273
274
275
276
277
278
279
280
281
282
283
284
   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) {
285
   RichString out;
286
   RichString_initVal(out);
Hisham Muhammad's avatar
Hisham Muhammad committed
287
288
289
290
291
292
293
294
295
296
297
298
299
   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) {
300
   Vector_prune(this->processes);
Hisham Muhammad's avatar
Hisham Muhammad committed
301
302
303
}

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

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

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

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

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

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

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

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

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

407
   assert(proc->pid == atoi(buf));
Hisham Muhammad's avatar
Hisham Muhammad committed
408
409
410
411
412
413
414
415
416
417
418
419
   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;
   
420
   #ifdef DEBUG_PROC
Hisham Muhammad's avatar
Hisham Muhammad committed
421
   int num = ProcessList_read(this, location, 
422
      "%c %u %u %u %u %d %lu %lu %lu %lu "
Hisham Muhammad's avatar
Hisham Muhammad committed
423
424
425
426
427
      "%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, 
428
429
430
      &proc->tpgid, &proc->flags,
      &proc->minflt, &proc->cminflt, &proc->majflt, &proc->cmajflt,
      &proc->utime, &proc->stime, &proc->cutime, &proc->cstime, 
431
      &proc->priority, &proc->nice, &proc->nlwp, &proc->itrealvalue,
Hisham Muhammad's avatar
Hisham Muhammad committed
432
433
434
435
436
      &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);
437
438
439
   #else
   long int uzero;
   int num = ProcessList_read(this, location, 
440
      "%c %u %u %u %u %d %lu %lu %lu %lu "
441
442
443
444
445
446
447
448
      "%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, 
449
      &proc->priority, &proc->nice, &proc->nlwp, &uzero,
450
451
452
453
454
455
      &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
456
457
458
459
460
461
462
463
464
   
   // 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
465
bool ProcessList_readStatusFile(ProcessList* this, Process* proc, char* dirname, char* name) {
Hisham Muhammad's avatar
Hisham Muhammad committed
466
467
   char statusfilename[MAX_NAME+1];
   statusfilename[MAX_NAME] = '\0';
468

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

502
bool ProcessList_processEntries(ProcessList* this, char* dirname, Process* parent, float period) {
Hisham Muhammad's avatar
Hisham Muhammad committed
503
504
505
506
507
   DIR* dir;
   struct dirent* entry;
   Process* prototype = this->prototype;

   dir = opendir(dirname);
508
509
510
   if (!dir) return false;
   int processors = this->processorCount;
   bool showUserlandThreads = !this->hideUserlandThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
   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;
      }

527
      if (pid > 0) {
Hisham Muhammad's avatar
Hisham Muhammad committed
528

Hisham Muhammad's avatar
Hisham Muhammad committed
529
530
531
532
         FILE* status;
         char statusfilename[MAX_NAME+1];
         char command[PROCESS_COMM_LEN + 1];

533
         Process* process = NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
534
         Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid);
535

536
         if (existingProcess) {
537
            assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1);
538
            process = existingProcess;
539
            assert(process->pid == pid);
540
         } else {
541
542
543
544
545
546
547
            if (parent && parent->pid == pid) {
               process = parent;
            } else {
               process = prototype;
               assert(process->comm == NULL);
               process->pid = pid;
            }
Hisham Muhammad's avatar
Hisham Muhammad committed
548
         }
549
550
551
552
553
554
555
556
557

         if (showUserlandThreads && (!parent || pid != parent->pid)) {
            char subdirname[MAX_NAME+1];
            snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
   
            if (ProcessList_processEntries(this, subdirname, process, period))
               continue;
         }

Hisham Muhammad's avatar
Hisham Muhammad committed
558
559
         process->updated = true;

560
561
562
563
         if (!existingProcess)
            if (! ProcessList_readStatusFile(this, process, dirname, name))
               goto errorReadingProcess;

564
565
566
567
568
569
570
571
         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, 
572
             &process->m_trs, &process->m_lrs, &process->m_drs, 
573
574
575
576
577
578
579
580
581
             &process->m_dt);

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

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

582
583
584
585
586
         int lasttimes = (process->utime + process->stime);

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

         int success = ProcessList_readStatFile(this, process, status, command);
         fclose(status);
592
         if(!success) {
593
            goto errorReadingProcess;
594
         }
595

Hisham Muhammad's avatar
Hisham Muhammad committed
596
         if(!existingProcess) {
597
            process->user = UsersTable_getRef(this->usersTable, process->st_uid);
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619

            #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
620
 
Hisham Muhammad's avatar
Hisham Muhammad committed
621
            snprintf(statusfilename, MAX_NAME, "%s/%s/cmdline", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
622
            status = ProcessList_fopen(this, statusfilename, "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
            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);
         }

639
         int percent_cpu = (process->utime + process->stime - lasttimes) / 
640
            period * 100.0;
641
         process->percent_cpu = MAX(MIN(percent_cpu, processors*100.0), 0.0);
642

643
644
         process->percent_mem = (process->m_resident * PAGE_SIZE) / 
            (float)(this->totalMem) * 
Hisham Muhammad's avatar
Hisham Muhammad committed
645
646
647
            100.0;

         this->totalTasks++;
Hisham Muhammad's avatar
Hisham Muhammad committed
648
649
650
         if (process->state == 'R') {
            this->runningTasks++;
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
651

652
         if (!existingProcess) {
653
654
            process = Process_clone(process);
            ProcessList_add(this, process);
655
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
656
657
658
659
660

         continue;

         // Exception handler.
         errorReadingProcess: {
661
662
663
664
            if (process->comm) {
               free(process->comm);
               process->comm = NULL;
            }
665
666
            if (existingProcess)
               ProcessList_remove(this, process);
667
            assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
668
669
670
671
         }
      }
   }
   closedir(dir);
672
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
673
674
675
}

void ProcessList_scan(ProcessList* this) {
676
   unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime;
677
   unsigned long long int swapFree;
Hisham Muhammad's avatar
Hisham Muhammad committed
678
679
680

   FILE* status;
   char buffer[128];
Hisham Muhammad's avatar
Hisham Muhammad committed
681
   status = ProcessList_fopen(this, PROCMEMINFOFILE, "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
682
   assert(status != NULL);
683
   int processors = this->processorCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
684
685
686
687
688
689
   while (!feof(status)) {
      fgets(buffer, 128, status);

      switch (buffer[0]) {
      case 'M':
         if (String_startsWith(buffer, "MemTotal:"))
690
            ProcessList_read(this, buffer, "MemTotal: %llu kB", &this->totalMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
691
         else if (String_startsWith(buffer, "MemFree:"))
692
            ProcessList_read(this, buffer, "MemFree: %llu kB", &this->freeMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
693
         else if (String_startsWith(buffer, "MemShared:"))
694
            ProcessList_read(this, buffer, "MemShared: %llu kB", &this->sharedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
695
696
697
         break;
      case 'B':
         if (String_startsWith(buffer, "Buffers:"))
698
            ProcessList_read(this, buffer, "Buffers: %llu kB", &this->buffersMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
699
700
701
         break;
      case 'C':
         if (String_startsWith(buffer, "Cached:"))
702
            ProcessList_read(this, buffer, "Cached: %llu kB", &this->cachedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
703
704
705
         break;
      case 'S':
         if (String_startsWith(buffer, "SwapTotal:"))
706
            ProcessList_read(this, buffer, "SwapTotal: %llu kB", &this->totalSwap);
Hisham Muhammad's avatar
Hisham Muhammad committed
707
         if (String_startsWith(buffer, "SwapFree:"))
708
            ProcessList_read(this, buffer, "SwapFree: %llu kB", &swapFree);
Hisham Muhammad's avatar
Hisham Muhammad committed
709
710
711
         break;
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
712

Hisham Muhammad's avatar
Hisham Muhammad committed
713
714
715
716
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
   fclose(status);

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

Hisham Muhammad's avatar
Hisham Muhammad committed
719
   assert(status != NULL);
720
   for (int i = 0; i <= processors; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
721
722
      char buffer[256];
      int cpuid;
723
      unsigned long long int ioWait, irq, softIrq, steal;
Hisham Muhammad's avatar
Hisham Muhammad committed
724
725
726
727
728
729
      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)
730
         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
731
      else {
732
         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
733
734
735
736
         assert(cpuid == i - 1);
      }
      // Fields existing on kernels >= 2.6
      // (and RHEL's patched kernel 2.4...)
737
738
739
      idlealltime = idletime + ioWait;
      systemalltime = systemtime + irq + softIrq + steal;
      totaltime = usertime + nicetime + systemalltime + idlealltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
740
741
742
743
744
      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]);
745
      assert (systemalltime >= this->systemAllTime[i]);
746
      assert (idlealltime >= this->idleAllTime[i]);
747
      assert (ioWait >= this->ioWaitTime[i]);
748
749
750
      assert (irq >= this->irqTime[i]);
      assert (softIrq >= this->softIrqTime[i]);
      assert (steal >= this->stealTime[i]);
Hisham Muhammad's avatar
Hisham Muhammad committed
751
752
753
      this->userPeriod[i] = usertime - this->userTime[i];
      this->nicePeriod[i] = nicetime - this->niceTime[i];
      this->systemPeriod[i] = systemtime - this->systemTime[i];
754
      this->systemAllPeriod[i] = systemalltime - this->systemAllTime[i];
755
      this->idleAllPeriod[i] = idlealltime - this->idleAllTime[i];
Hisham Muhammad's avatar
Hisham Muhammad committed
756
      this->idlePeriod[i] = idletime - this->idleTime[i];
757
758
759
760
      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
761
762
763
764
      this->totalPeriod[i] = totaltime - this->totalTime[i];
      this->userTime[i] = usertime;
      this->niceTime[i] = nicetime;
      this->systemTime[i] = systemtime;
765
      this->systemAllTime[i] = systemalltime;
766
      this->idleAllTime[i] = idlealltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
767
      this->idleTime[i] = idletime;
768
769
770
771
      this->ioWaitTime[i] = ioWait;
      this->irqTime[i] = irq;
      this->softIrqTime[i] = softIrq;
      this->stealTime[i] = steal;
Hisham Muhammad's avatar
Hisham Muhammad committed
772
773
      this->totalTime[i] = totaltime;
   }
774
   float period = (float)this->totalPeriod[0] / processors;
Hisham Muhammad's avatar
Hisham Muhammad committed
775
776
777
   fclose(status);

   // mark all process as "dirty"
778
779
   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
780
781
782
783
784
      p->updated = false;
   }
   
   this->totalTasks = 0;
   this->runningTasks = 0;
785
786

   ProcessList_processEntries(this, PROCDIR, NULL, period);
Hisham Muhammad's avatar
Hisham Muhammad committed
787
   
788
789
   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
790
791
792
793
794
795
796
      if (p->updated == false)
         ProcessList_remove(this, p);
      else
         p->updated = false;
   }

}