ProcessList.c 33.7 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
3
4
5
6
7
8
/*
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.
*/

#include "ProcessList.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
9
10

#include "CRT.h"
11
#include "String.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
12

Hisham Muhammad's avatar
Hisham Muhammad committed
13
14
#include <sys/time.h>
#include <sys/utsname.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
15
16
17
18
19
20
21
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <stdbool.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
22
#include <stdarg.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
23
#include <math.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
24
25
#include <string.h>
#include <time.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
26
#include <assert.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
27
28
29
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
30
31

/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
32
33
34
35
36
#include "Vector.h"
#include "Hashtable.h"
#include "UsersTable.h"
#include "Panel.h"
#include "Process.h"
37

Hisham Muhammad's avatar
Hisham Muhammad committed
38
39
40
41
42
#ifndef PROCDIR
#define PROCDIR "/proc"
#endif

#ifndef PROCSTATFILE
43
#define PROCSTATFILE PROCDIR "/stat"
Hisham Muhammad's avatar
Hisham Muhammad committed
44
45
46
#endif

#ifndef PROCMEMINFOFILE
47
#define PROCMEMINFOFILE PROCDIR "/meminfo"
Hisham Muhammad's avatar
Hisham Muhammad committed
48
49
50
#endif

#ifndef MAX_NAME
Hisham Muhammad's avatar
Hisham Muhammad committed
51
52
53
54
#define MAX_NAME 128
#endif

#ifndef MAX_READ
55
#define MAX_READ 2048
Hisham Muhammad's avatar
Hisham Muhammad committed
56
57
#endif

58
#ifndef ProcessList_cpuId
59
#define ProcessList_cpuId(pl, cpu) ((pl)->countCPUsFromZero ? (cpu) : (cpu)+1)
60
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
61

62
63
64
65
66
67
68
69
70
71
72
typedef enum TreeStr_ {
   TREE_STR_HORZ,
   TREE_STR_VERT,
   TREE_STR_RTEE,
   TREE_STR_BEND,
   TREE_STR_TEND,
   TREE_STR_OPEN,
   TREE_STR_SHUT,
   TREE_STR_COUNT
} TreeStr;

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
typedef struct CPUData_ {
   unsigned long long int totalTime;
   unsigned long long int userTime;
   unsigned long long int systemTime;
   unsigned long long int systemAllTime;
   unsigned long long int idleAllTime;
   unsigned long long int idleTime;
   unsigned long long int niceTime;
   unsigned long long int ioWaitTime;
   unsigned long long int irqTime;
   unsigned long long int softIrqTime;
   unsigned long long int stealTime;
   unsigned long long int guestTime;
   
   unsigned long long int totalPeriod;
   unsigned long long int userPeriod;
   unsigned long long int systemPeriod;
   unsigned long long int systemAllPeriod;
   unsigned long long int idleAllPeriod;
   unsigned long long int idlePeriod;
   unsigned long long int nicePeriod;
   unsigned long long int ioWaitPeriod;
   unsigned long long int irqPeriod;
   unsigned long long int softIrqPeriod;
   unsigned long long int stealPeriod;
   unsigned long long int guestPeriod;
} CPUData;

Hisham Muhammad's avatar
Hisham Muhammad committed
101
typedef struct ProcessList_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
102
   const char **treeStr;
103
104
   Vector* processes;
   Vector* processes2;
Hisham Muhammad's avatar
Hisham Muhammad committed
105
106
107
   Hashtable* processTable;
   UsersTable* usersTable;

108
   Panel* panel;
109
   int following;
110
111
   uid_t userId;
   const char* incFilter;
112
   Hashtable* pidWhiteList;
113

114
   int cpuCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
115
   int totalTasks;
116
117
   int userlandThreads;
   int kernelThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
118
119
   int runningTasks;

120
   #ifdef HAVE_LIBHWLOC
121
122
123
   hwloc_topology_t topology;
   bool topologyOk;
   #endif
124
   CPUData* cpus;
125
126
127
128
129
130
131
132
133
134

   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
135

136
   int flags;
Hisham Muhammad's avatar
Hisham Muhammad committed
137
138
139
140
141
   ProcessField* fields;
   ProcessField sortKey;
   int direction;
   bool hideThreads;
   bool shadowOtherUsers;
Hisham Muhammad's avatar
Hisham Muhammad committed
142
143
   bool showThreadNames;
   bool showingThreadNames;
Hisham Muhammad's avatar
Hisham Muhammad committed
144
145
146
147
148
   bool hideKernelThreads;
   bool hideUserlandThreads;
   bool treeView;
   bool highlightBaseName;
   bool highlightMegabytes;
149
   bool highlightThreads;
150
   bool detailedCPUTime;
151
   bool countCPUsFromZero;
152
   bool updateProcessNames;
153
   bool accountGuestInCPUMeter;
Hisham Muhammad's avatar
Hisham Muhammad committed
154
   bool userOnly;
Hisham Muhammad's avatar
Hisham Muhammad committed
155
156

} ProcessList;
157

Hisham Muhammad's avatar
Hisham Muhammad committed
158
159
}*/

160
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
161

162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
const char *ProcessList_treeStrAscii[TREE_STR_COUNT] = {
   "-", // TREE_STR_HORZ
   "|", // TREE_STR_VERT
   "`", // TREE_STR_RTEE
   "`", // TREE_STR_BEND
   ",", // TREE_STR_TEND
   "+", // TREE_STR_OPEN
   "-", // TREE_STR_SHUT
};

const char *ProcessList_treeStrUtf8[TREE_STR_COUNT] = {
   "\xe2\x94\x80", // TREE_STR_HORZ ─
   "\xe2\x94\x82", // TREE_STR_VERT │
   "\xe2\x94\x9c", // TREE_STR_RTEE ├
   "\xe2\x94\x94", // TREE_STR_BEND └
   "\xe2\x94\x8c", // TREE_STR_TEND ┌
   "+",            // TREE_STR_OPEN +
   "\xe2\x94\x80", // TREE_STR_SHUT ─
};

Hisham Muhammad's avatar
Hisham Muhammad committed
182
183
184
static ssize_t xread(int fd, void *buf, size_t count) {
  // Read some bytes. Retry on EINTR and when we don't get as many bytes as we requested.
  size_t alreadyRead = 0;
185
186
187
188
189
190
191
192
193
194
  for(;;) {
     ssize_t res = read(fd, buf, count);
     if (res == -1 && errno == EINTR) continue;
     if (res > 0) {
       buf = ((char*)buf)+res;
       count -= res;
       alreadyRead += res;
     }
     if (res == -1) return -1;
     if (count == 0 || res == 0) return alreadyRead;
Hisham Muhammad's avatar
Hisham Muhammad committed
195
196
197
  }
}

198
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidWhiteList) {
Hisham Muhammad's avatar
Hisham Muhammad committed
199
   ProcessList* this;
200
   this = calloc(1, sizeof(ProcessList));
201
   this->processes = Vector_new(Class(Process), true, DEFAULT_SIZE);
202
   this->processTable = Hashtable_new(140, false);
Hisham Muhammad's avatar
Hisham Muhammad committed
203
   this->usersTable = usersTable;
204
   this->pidWhiteList = pidWhiteList;
Hisham Muhammad's avatar
Hisham Muhammad committed
205
206
   
   /* tree-view auxiliary buffers */
207
   this->processes2 = Vector_new(Class(Process), true, DEFAULT_SIZE);
Hisham Muhammad's avatar
Hisham Muhammad committed
208
   
209
   FILE* file = fopen(PROCSTATFILE, "r");
210
211
212
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCSTATFILE);
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
213
   char buffer[256];
214
   int cpus = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
215
   do {
216
      cpus++;
217
      fgets(buffer, 255, file);
Hisham Muhammad's avatar
Hisham Muhammad committed
218
   } while (String_startsWith(buffer, "cpu"));
219
   fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
220
   this->cpuCount = MAX(cpus - 1, 1);
221

222
#ifdef HAVE_LIBHWLOC
223
224
225
226
   this->topologyOk = false;
   int topoErr = hwloc_topology_init(&this->topology);
   if (topoErr == 0) {
      topoErr = hwloc_topology_load(this->topology);
Hisham Muhammad's avatar
Hisham Muhammad committed
227
228
   }
   if (topoErr == 0) {
229
230
231
      this->topologyOk = true;
   }
#endif
232
   this->cpus = calloc(cpus, sizeof(CPUData));
233

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

239
   this->fields = calloc(LAST_PROCESSFIELD+1, sizeof(ProcessField));
240
   // TODO: turn 'fields' into a Vector,
Hisham Muhammad's avatar
Hisham Muhammad committed
241
   // (and ProcessFields into proper objects).
242
   this->flags = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
243
244
   for (int i = 0; defaultHeaders[i]; i++) {
      this->fields[i] = defaultHeaders[i];
245
      this->flags |= Process_fieldFlags[defaultHeaders[i]];
Hisham Muhammad's avatar
Hisham Muhammad committed
246
   }
247
248
249
250
251

   #ifdef HAVE_OPENVZ
   this->flags |= PROCESS_FLAG_OPENVZ;
   #endif

Hisham Muhammad's avatar
Hisham Muhammad committed
252
253
254
255
   this->sortKey = PERCENT_CPU;
   this->direction = 1;
   this->hideThreads = false;
   this->shadowOtherUsers = false;
256
257
   this->showThreadNames = false;
   this->showingThreadNames = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
258
259
260
261
262
   this->hideKernelThreads = false;
   this->hideUserlandThreads = false;
   this->treeView = false;
   this->highlightBaseName = false;
   this->highlightMegabytes = false;
263
   this->detailedCPUTime = false;
264
   this->countCPUsFromZero = false;
265
   this->updateProcessNames = false;
266
   this->treeStr = NULL;
267
   this->following = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
268

269
270
271
   if (CRT_utf8)
      this->treeStr = CRT_utf8 ? ProcessList_treeStrUtf8 : ProcessList_treeStrAscii;

Hisham Muhammad's avatar
Hisham Muhammad committed
272
273
274
275
276
   return this;
}

void ProcessList_delete(ProcessList* this) {
   Hashtable_delete(this->processTable);
277
278
   Vector_delete(this->processes);
   Vector_delete(this->processes2);
279
   free(this->cpus);
Hisham Muhammad's avatar
Hisham Muhammad committed
280
281
282
283
   free(this->fields);
   free(this);
}

284
285
286
287
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
   this->panel = panel;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
288
289
290
291
292
293
294
void ProcessList_invertSortOrder(ProcessList* this) {
   if (this->direction == 1)
      this->direction = -1;
   else
      this->direction = 1;
}

295
296
void ProcessList_printHeader(ProcessList* this, RichString* header) {
   RichString_prune(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
297
298
   ProcessField* fields = this->fields;
   for (int i = 0; fields[i]; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
299
      const char* field = Process_fieldTitles[fields[i]];
300
      if (!this->treeView && this->sortKey == fields[i])
301
         RichString_append(header, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
Hisham Muhammad's avatar
Hisham Muhammad committed
302
      else
303
         RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field);
Hisham Muhammad's avatar
Hisham Muhammad committed
304
305
306
   }
}

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

319
static void ProcessList_remove(ProcessList* this, Process* p) {
320
321
322
   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);
323
   assert(pp == p); (void)pp;
324
   unsigned int pid = p->pid;
Hisham Muhammad's avatar
Hisham Muhammad committed
325
326
327
   int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
   assert(idx != -1);
   if (idx >= 0) Vector_remove(this->processes, idx);
328
   assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
329
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
330
331
}

Hisham Muhammad's avatar
Hisham Muhammad committed
332
333
Process* ProcessList_get(ProcessList* this, int idx) {
   return (Process*) (Vector_get(this->processes, idx));
Hisham Muhammad's avatar
Hisham Muhammad committed
334
335
336
}

int ProcessList_size(ProcessList* this) {
337
   return (Vector_size(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
338
339
}

Hisham Muhammad's avatar
Hisham Muhammad committed
340
static void ProcessList_buildTree(ProcessList* this, pid_t pid, int level, int indent, int direction, bool show) {
341
   Vector* children = Vector_new(Class(Process), false, DEFAULT_SIZE);
Hisham Muhammad's avatar
Hisham Muhammad committed
342

343
   for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
344
      Process* process = (Process*) (Vector_get(this->processes, i));
345
      if (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid)) {
Hisham Muhammad's avatar
Hisham Muhammad committed
346
         process = (Process*) (Vector_take(this->processes, i));
347
         Vector_add(children, process);
Hisham Muhammad's avatar
Hisham Muhammad committed
348
349
      }
   }
350
   int size = Vector_size(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
351
   for (int i = 0; i < size; i++) {
352
      Process* process = (Process*) (Vector_get(children, i));
353
354
355
356
357
358
359
360
361
      if (!show)
         process->show = false;
      int s = this->processes2->items;
      if (direction == 1)
         Vector_add(this->processes2, process);
      else
         Vector_insert(this->processes2, 0, process);
      assert(this->processes2->items == s+1); (void)s;
      int nextIndent = indent | (1 << level);
362
      ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false);
363
364
365
366
      if (i == size - 1)
         process->indent = -nextIndent;
      else
         process->indent = nextIndent;
Hisham Muhammad's avatar
Hisham Muhammad committed
367
   }
368
   Vector_delete(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
369
370
371
372
}

void ProcessList_sort(ProcessList* this) {
   if (!this->treeView) {
373
      Vector_insertionSort(this->processes);
Hisham Muhammad's avatar
Hisham Muhammad committed
374
   } else {
375
      // Save settings
Hisham Muhammad's avatar
Hisham Muhammad committed
376
377
      int direction = this->direction;
      int sortKey = this->sortKey;
378
      // Sort by PID
Hisham Muhammad's avatar
Hisham Muhammad committed
379
380
      this->sortKey = PID;
      this->direction = 1;
381
      Vector_quickSort(this->processes);
382
      // Restore settings
Hisham Muhammad's avatar
Hisham Muhammad committed
383
384
      this->sortKey = sortKey;
      this->direction = direction;
385
      // Take PID 1 as root and add to the new listing
386
      int vsize = Vector_size(this->processes);
387
      Process* init = (Process*) (Vector_take(this->processes, 0));
388
389
390
      // This assertion crashes on hardened kernels.
      // I wonder how well tree view works on those systems.
      // assert(init->pid == 1);
Hisham Muhammad's avatar
Hisham Muhammad committed
391
      init->indent = 0;
392
      Vector_add(this->processes2, init);
393
      // Recursively empty list
Hisham Muhammad's avatar
Hisham Muhammad committed
394
      ProcessList_buildTree(this, init->pid, 0, 0, direction, true);
395
      // Add leftovers
396
397
398
399
      while (Vector_size(this->processes)) {
         Process* p = (Process*) (Vector_take(this->processes, 0));
         p->indent = 0;
         Vector_add(this->processes2, p);
Hisham Muhammad's avatar
Hisham Muhammad committed
400
         ProcessList_buildTree(this, p->pid, 0, 0, direction, p->showChildren);
401
402
403
      }
      assert(Vector_size(this->processes2) == vsize); (void)vsize;
      assert(Vector_size(this->processes) == 0);
404
      // Swap listings around
405
      Vector* t = this->processes;
Hisham Muhammad's avatar
Hisham Muhammad committed
406
407
408
409
410
      this->processes = this->processes2;
      this->processes2 = t;
   }
}

411
412
413
static bool ProcessList_readStatFile(Process *process, const char* dirname, const char* name, char* command) {
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
414
415
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
416
417
      return false;

Hisham Muhammad's avatar
Hisham Muhammad committed
418
   static char buf[MAX_READ+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
419

Hisham Muhammad's avatar
Hisham Muhammad committed
420
421
   int size = xread(fd, buf, MAX_READ);
   close(fd);
Hisham Muhammad's avatar
Hisham Muhammad committed
422
   if (size <= 0) return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
423
   buf[size] = '\0';
Hisham Muhammad's avatar
Hisham Muhammad committed
424

425
   assert(process->pid == atoi(buf));
Hisham Muhammad's avatar
Hisham Muhammad committed
426
   char *location = strchr(buf, ' ');
Hisham Muhammad's avatar
Hisham Muhammad committed
427
   if (!location) return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
428
429
430

   location += 2;
   char *end = strrchr(location, ')');
Hisham Muhammad's avatar
Hisham Muhammad committed
431
   if (!end) return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
432
433
434
435
436
   
   int commsize = end - location;
   memcpy(command, location, commsize);
   command[commsize] = '\0';
   location = end + 2;
437

Hisham Muhammad's avatar
Hisham Muhammad committed
438
439
440
441
442
443
444
445
446
447
448
449
450
451
   process->state = location[0];
   location += 2;
   process->ppid = strtol(location, &location, 10);
   location += 1;
   process->pgrp = strtoul(location, &location, 10);
   location += 1;
   process->session = strtoul(location, &location, 10);
   location += 1;
   process->tty_nr = strtoul(location, &location, 10);
   location += 1;
   process->tpgid = strtol(location, &location, 10);
   location += 1;
   process->flags = strtoul(location, &location, 10);
   location += 1;
452
453
454
455
456
457
458
459
   process->minflt = strtoull(location, &location, 10);
   location += 1;
   process->cminflt = strtoull(location, &location, 10);
   location += 1;
   process->majflt = strtoull(location, &location, 10);
   location += 1;
   process->cmajflt = strtoull(location, &location, 10);
   location += 1;
Hisham Muhammad's avatar
Hisham Muhammad committed
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
   process->utime = strtoull(location, &location, 10);
   location += 1;
   process->stime = strtoull(location, &location, 10);
   location += 1;
   process->cutime = strtoull(location, &location, 10);
   location += 1;
   process->cstime = strtoull(location, &location, 10);
   location += 1;
   process->priority = strtol(location, &location, 10);
   location += 1;
   process->nice = strtol(location, &location, 10);
   location += 1;
   process->nlwp = strtol(location, &location, 10);
   location += 1;
   for (int i=0; i<17; i++) location = strchr(location, ' ')+1;
   process->exit_signal = strtol(location, &location, 10);
   location += 1;
   assert(location != NULL);
   process->processor = strtol(location, &location, 10);
   assert(location == NULL);

   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
482
483
}

Hisham Muhammad's avatar
Hisham Muhammad committed
484
static bool ProcessList_statProcessDir(Process* process, const char* dirname, char* name, time_t curTime) {
485
486
   char filename[MAX_NAME+1];
   filename[MAX_NAME] = '\0';
487

488
   snprintf(filename, MAX_NAME, "%s/%s", dirname, name);
489
   struct stat sstat;
490
   int statok = stat(filename, &sstat);
491
492
   if (statok == -1)
      return false;
493
   process->st_uid = sstat.st_uid;
Hisham Muhammad's avatar
Hisham Muhammad committed
494
495
496
  
   struct tm date;
   time_t ctime = sstat.st_ctime;
497
   process->starttime_ctime = ctime;
Hisham Muhammad's avatar
Hisham Muhammad committed
498
   (void) localtime_r((time_t*) &ctime, &date);
Hisham Muhammad's avatar
Hisham Muhammad committed
499
   strftime(process->starttime_show, 7, ((ctime > curTime - 86400) ? "%R " : "%b%d "), &date);
Hisham Muhammad's avatar
Hisham Muhammad committed
500
   
501
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
502
503
}

504
#ifdef HAVE_TASKSTATS
505

Hisham Muhammad's avatar
Hisham Muhammad committed
506
static void ProcessList_readIoFile(Process* process, const char* dirname, char* name, unsigned long long now) {
507
508
   char filename[MAX_NAME+1];
   filename[MAX_NAME] = '\0';
509

510
   snprintf(filename, MAX_NAME, "%s/%s/io", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
511
512
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
513
514
      return;
   
Hisham Muhammad's avatar
Hisham Muhammad committed
515
516
517
518
519
   char buffer[1024];
   ssize_t buflen = xread(fd, buffer, 1023);
   close(fd);
   if (buflen < 1) return;
   buffer[buflen] = '\0';
520
521
   unsigned long long last_read = process->io_read_bytes;
   unsigned long long last_write = process->io_write_bytes;
Hisham Muhammad's avatar
Hisham Muhammad committed
522
523
524
525
   char *buf = buffer;
   char *line = NULL;
   while ((line = strsep(&buf, "\n")) != NULL) {
      switch (line[0]) {
526
      case 'r':
Hisham Muhammad's avatar
Hisham Muhammad committed
527
528
529
530
         if (line[1] == 'c' && strncmp(line+2, "har: ", 5) == 0)
            process->io_rchar = strtoull(line+7, NULL, 10);
         else if (strncmp(line+1, "ead_bytes: ", 11) == 0) {
            process->io_read_bytes = strtoull(line+12, NULL, 10);
531
532
533
534
535
536
            process->io_rate_read_bps = 
               ((double)(process->io_read_bytes - last_read))/(((double)(now - process->io_rate_read_time))/1000);
            process->io_rate_read_time = now;
         }
         break;
      case 'w':
Hisham Muhammad's avatar
Hisham Muhammad committed
537
538
539
540
         if (line[1] == 'c' && strncmp(line+2, "har: ", 5) == 0)
            process->io_wchar = strtoull(line+7, NULL, 10);
         else if (strncmp(line+1, "rite_bytes: ", 12) == 0) {
            process->io_write_bytes = strtoull(line+13, NULL, 10);
541
542
543
544
545
546
            process->io_rate_write_bps = 
               ((double)(process->io_write_bytes - last_write))/(((double)(now - process->io_rate_write_time))/1000);
            process->io_rate_write_time = now;
         }
         break;
      case 's':
Hisham Muhammad's avatar
Hisham Muhammad committed
547
548
549
         if (line[5] == 'r' && strncmp(line+1, "yscr: ", 6) == 0)
            process->io_syscr = strtoull(line+7, NULL, 10);
         else if (strncmp(line+1, "yscw: ", 6) == 0)
550
            sscanf(line, "syscw: %32llu", &process->io_syscw);
Hisham Muhammad's avatar
Hisham Muhammad committed
551
            process->io_syscw = strtoull(line+7, NULL, 10);
552
553
         break;
      case 'c':
Hisham Muhammad's avatar
Hisham Muhammad committed
554
555
         if (strncmp(line+1, "ancelled_write_bytes: ", 22) == 0)
           process->io_cancelled_write_bytes = strtoull(line+23, NULL, 10);
556
557
558
559
560
561
562
563
564
      }
   }
}

#endif

static bool ProcessList_readStatmFile(Process* process, const char* dirname, const char* name) {
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/statm", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
565
566
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
567
      return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
   char buf[256];
   ssize_t rres = xread(fd, buf, 255);
   close(fd);
   if (rres < 1) return false;

   char *p = buf;
   errno = 0;
   process->m_size = strtol(p, &p, 10); if (*p == ' ') p++;
   process->m_resident = strtol(p, &p, 10); if (*p == ' ') p++;
   process->m_share = strtol(p, &p, 10); if (*p == ' ') p++;
   process->m_trs = strtol(p, &p, 10); if (*p == ' ') p++;
   process->m_lrs = strtol(p, &p, 10); if (*p == ' ') p++;
   process->m_drs = strtol(p, &p, 10); if (*p == ' ') p++;
   process->m_dt = strtol(p, &p, 10);
   return (errno == 0);
583
584
585
586
}

#ifdef HAVE_OPENVZ

587
static void ProcessList_readOpenVZData(ProcessList* this, Process* process, const char* dirname, const char* name) {
588
   if ( (!(this->flags & PROCESS_FLAG_OPENVZ)) || (access("/proc/vz", R_OK) != 0)) {
589
590
      process->vpid = process->pid;
      process->ctid = 0;
591
      this->flags |= ~PROCESS_FLAG_OPENVZ;
592
593
594
595
596
597
598
599
      return;
   }
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/stat", dirname, name);
   FILE* file = fopen(filename, "r");
   if (!file) 
      return;
   fscanf(file, 
600
601
602
603
604
605
606
      "%*32u %*32s %*1c %*32u %*32u %*32u %*32u %*32u %*32u %*32u "
      "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u "
      "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u "
      "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u "
      "%*32u %*32u %*32u %*32u %*32u %*32u %*32u %*32u "
      "%*32u %*32u %*32u %*32u %*32u %*32u %*32u "
      "%*32u %*32u %32u %32u",
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
      &process->vpid, &process->ctid);
   fclose(file);
}

#endif

#ifdef HAVE_CGROUP

static void ProcessList_readCGroupFile(Process* process, const char* dirname, const char* name) {
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/cgroup", dirname, name);
   FILE* file = fopen(filename, "r");
   if (!file) {
      process->cgroup = strdup("");
      return;
   }
   char buffer[256];
   char *ok = fgets(buffer, 255, file);
   if (ok) {
      char* trimmed = String_trim(buffer);
627
628
      int nFields;
      char** fields = String_split(trimmed, ':', &nFields);
629
      free(trimmed);
630
631
632
633
634
      if (nFields >= 3) {
         process->cgroup = strndup(fields[2] + 1, 10);
      } else {
         process->cgroup = strdup("");
      }
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
      String_freeArray(fields);
   }
   fclose(file);
}

#endif

#ifdef HAVE_VSERVER

static void ProcessList_readVServerData(Process* process, const char* dirname, const char* name) {
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/status", dirname, name);
   FILE* file = fopen(filename, "r");
   if (!file)
      return;
   char buffer[256];
   process->vxid = 0;
   while (fgets(buffer, 255, file)) {
      if (String_startsWith(buffer, "VxID:")) {
         int vxid;
655
         int ok = sscanf(buffer, "VxID:\t%32d", &vxid);
656
657
         if (ok >= 1) {
            process->vxid = vxid;
658
         }
659
660
661
662
      }
      #if defined HAVE_ANCIENT_VSERVER
      else if (String_startsWith(buffer, "s_context:")) {
         int vxid;
663
         int ok = sscanf(buffer, "s_context:\t%32d", &vxid);
664
665
         if (ok >= 1) {
            process->vxid = vxid;
666
667
         }
      }
668
      #endif
669
   }
670
   fclose(file);
671
}
672

673
674
#endif

675
676
677
678
679
680
681
#ifdef HAVE_OOM

static void ProcessList_readOomData(Process* process, const char* dirname, const char* name) {
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/oom_score", dirname, name);
   FILE* file = fopen(filename, "r");
   if (!file)
682
      return;
683
   char buffer[256];
684
685
   if (fgets(buffer, 255, file)) {
      unsigned int oom;
686
      int ok = sscanf(buffer, "%32u", &oom);
687
688
689
      if (ok >= 1) {
         process->oom = oom;
      }
690
691
692
693
694
695
   }
   fclose(file);
}

#endif

696
697
698
static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
   if (Process_isKernelThread(process))
      return true;
699

700
701
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
702
703
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
704
705
706
      return false;
         
   char command[4096+1]; // max cmdline length on Linux
Hisham Muhammad's avatar
Hisham Muhammad committed
707
708
   int amtRead = xread(fd, command, sizeof(command) - 1);
   close(fd);
709
   int tokenEnd = 0; 
710
711
712
   if (amtRead > 0) {
      for (int i = 0; i < amtRead; i++)
         if (command[i] == '\0' || command[i] == '\n') {
713
714
715
            if (tokenEnd == 0) {
               tokenEnd = i;
            }
716
717
718
            command[i] = ' ';
         }
   }
719
720
721
   if (tokenEnd == 0) {
      tokenEnd = amtRead;
   }
722
723
   command[amtRead] = '\0';
   free(process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
724
   process->comm = strdup(command);
725
   process->basenameOffset = tokenEnd;
726

727
728
729
730
   return true;
}


Hisham Muhammad's avatar
Hisham Muhammad committed
731
static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
Hisham Muhammad's avatar
Hisham Muhammad committed
732
733
734
   DIR* dir;
   struct dirent* entry;

Hisham Muhammad's avatar
Hisham Muhammad committed
735
736
   time_t curTime = tv.tv_sec;
   #ifdef HAVE_TASKSTATS
Hisham Muhammad's avatar
Hisham Muhammad committed
737
   unsigned long long now = tv.tv_sec*1000LL+tv.tv_usec/1000LL;
Hisham Muhammad's avatar
Hisham Muhammad committed
738
739
   #endif

Hisham Muhammad's avatar
Hisham Muhammad committed
740
   dir = opendir(dirname);
741
   if (!dir) return false;
742
   int cpus = this->cpuCount;
743
744
   bool hideKernelThreads = this->hideKernelThreads;
   bool hideUserlandThreads = this->hideUserlandThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
745
746
   while ((entry = readdir(dir)) != NULL) {
      char* name = entry->d_name;
Hisham Muhammad's avatar
Hisham Muhammad committed
747
748
749
750
751
752
753
754

      // The RedHat kernel hides threads with a dot.
      // I believe this is non-standard.
      if ((!this->hideThreads) && name[0] == '.') {
         name++;
      }

      // Just skip all non-number directories.
755
      if (name[0] < '0' || name[0] > '9') {
Hisham Muhammad's avatar
Hisham Muhammad committed
756
         continue;
757
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
758

Hisham Muhammad's avatar
Hisham Muhammad committed
759
      // filename is a number: process directory
760
761
762
      int pid = atoi(name);
     
      if (parent && pid == parent->pid)
763
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
764

765
766
      if (pid <= 0) 
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
767

768
769
770
771
772
773
774
775
776
777
778
      Process* process = NULL;
      Process* existingProcess = (Process*) Hashtable_get(this->processTable, pid);

      if (existingProcess) {
         assert(Vector_indexOf(this->processes, existingProcess, Process_pidCompare) != -1);
         process = existingProcess;
         assert(process->pid == pid);
      } else {
         process = Process_new(this);
         assert(process->comm == NULL);
         process->pid = pid;
779
         process->tgid = parent ? parent->pid : pid;
780
      }
781

782
783
      char subdirname[MAX_NAME+1];
      snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
784
      ProcessList_processEntries(this, subdirname, process, period, tv);
785

786
      #ifdef HAVE_TASKSTATS
787
788
      if (this->flags & PROCESS_FLAG_IO)
         ProcessList_readIoFile(process, dirname, name, now);
789
      #endif
790

791
792
      if (! ProcessList_readStatmFile(process, dirname, name))
         goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
793

794
      process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
795

796
      char command[MAX_NAME+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
797
      unsigned long long int lasttimes = (process->utime + process->stime);
798
799
      if (! ProcessList_readStatFile(process, dirname, name, command))
         goto errorReadingProcess;
800
801
      if (this->flags & PROCESS_FLAG_IOPRIO)
         Process_updateIOPriority(process);
802
      float percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0;
803
804
      process->percent_cpu = MAX(MIN(percent_cpu, cpus*100.0), 0.0);
      if (isnan(process->percent_cpu)) process->percent_cpu = 0.0;
Hisham Muhammad's avatar
Hisham Muhammad committed
805
      process->percent_mem = (process->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem) * 100.0;
806

807
      if(!existingProcess) {
808

Hisham Muhammad's avatar
Hisham Muhammad committed
809
         if (! ProcessList_statProcessDir(process, dirname, name, curTime))
810
811
            goto errorReadingProcess;

812
813
         process->user = UsersTable_getRef(this->usersTable, process->st_uid);

814
         #ifdef HAVE_OPENVZ
815
         ProcessList_readOpenVZData(this, process, dirname, name);
816
         #endif
817
         
818
         #ifdef HAVE_VSERVER
819
820
         if (this->flags & PROCESS_FLAG_VSERVER)
            ProcessList_readVServerData(process, dirname, name);
821
         #endif
822

823
         if (! ProcessList_readCmdlineFile(process, dirname, name))
824
825
            goto errorReadingProcess;

826
         ProcessList_add(this, process);
827
828
829
830
831
      } else {
         if (this->updateProcessNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
         }
832
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
833

834
835
836
837
838
839
840
841
842
      #ifdef HAVE_CGROUP
      if (this->flags & PROCESS_FLAG_CGROUP)
         ProcessList_readCGroupFile(process, dirname, name);
      #endif
      
      #ifdef HAVE_OOM
      ProcessList_readOomData(process, dirname, name);
      #endif

843
844
      if (process->state == 'Z') {
         free(process->comm);
845
         process->basenameOffset = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
846
         process->comm = strdup(command);
847
      } else if (Process_isThread(process)) {
848
         if (this->showThreadNames || Process_isKernelThread(process) || process->state == 'Z') {
849
            free(process->comm);
850
            process->basenameOffset = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
851
            process->comm = strdup(command);
852
853
854
         } else if (this->showingThreadNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
855
         }
856
857
858
859
860
         if (Process_isKernelThread(process)) {
            this->kernelThreads++;
         } else {
            this->userlandThreads++;
         }
861
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
862

863
864
865
866
      this->totalTasks++;
      if (process->state == 'R')
         this->runningTasks++;
      process->updated = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
867

868
      continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
869

870
871
872
873
      // Exception handler.
      errorReadingProcess: {
         if (process->comm) {
            free(process->comm);
874
            process->basenameOffset = -1;
875
            process->comm = NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
876
         }
877
878
879
880
         if (existingProcess)
            ProcessList_remove(this, process);
         else
            Process_delete((Object*)process);
Hisham Muhammad's avatar
Hisham Muhammad committed
881
882
883
      }
   }
   closedir(dir);
884
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
885
886
887
}

void ProcessList_scan(ProcessList* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
888
   unsigned long long int usertime, nicetime, systemtime, idletime;
Hisham Muhammad's avatar
Hisham Muhammad committed
889
   unsigned long long int swapFree = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
890

891
   FILE* file = fopen(PROCMEMINFOFILE, "r");
892
893
894
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCMEMINFOFILE);
   }
895
   int cpus = this->cpuCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
896
   assert(cpus > 0);
Hisham Muhammad's avatar
Hisham Muhammad committed
897
898
   {
      char buffer[128];
899
      while (fgets(buffer, 128, file)) {
Hisham Muhammad's avatar
Hisham Muhammad committed
900
901
902
903
   
         switch (buffer[0]) {
         case 'M':
            if (String_startsWith(buffer, "MemTotal:"))
904
               sscanf(buffer, "MemTotal: %32llu kB", &this->totalMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
905
            else if (String_startsWith(buffer, "MemFree:"))
906
               sscanf(buffer, "MemFree: %32llu kB", &this->freeMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
907
            else if (String_startsWith(buffer, "MemShared:"))
908
               sscanf(buffer, "MemShared: %32llu kB", &this->sharedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
909
910
911
            break;
         case 'B':
            if (String_startsWith(buffer, "Buffers:"))
912
               sscanf(buffer, "Buffers: %32llu kB", &this->buffersMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
913
914
915
            break;
         case 'C':
            if (String_startsWith(buffer, "Cached:"))
916
               sscanf(buffer, "Cached: %32llu kB", &this->cachedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
917
918
919
            break;
         case 'S':
            if (String_startsWith(buffer, "SwapTotal:"))
920
               sscanf(buffer, "SwapTotal: %32llu kB", &this->totalSwap);
Hisham Muhammad's avatar
Hisham Muhammad committed
921
            if (String_startsWith(buffer, "SwapFree:"))
922
               sscanf(buffer, "SwapFree: %32llu kB", &swapFree);
Hisham Muhammad's avatar
Hisham Muhammad committed
923
924
            break;
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
925
926
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
927

Hisham Muhammad's avatar
Hisham Muhammad committed
928
929
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
930
   fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
931

932
   file = fopen(PROCSTATFILE, "r");
933
934
935
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCSTATFILE);
   }
936
   for (int i = 0; i <= cpus; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
937
938
      char buffer[256];
      int cpuid;
939
      unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
Hisham Muhammad's avatar
Hisham Muhammad committed
940
      unsigned long long int systemalltime, idlealltime, totaltime, virtalltime;
941
      ioWait = irq = softIrq = steal = guest = guestnice = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
942
      // Dependending on your kernel version,
943
      // 5, 7, 8 or 9 of these fields will be set.
Hisham Muhammad's avatar
Hisham Muhammad committed
944
      // The rest will remain at zero.
945
      fgets(buffer, 255, file);
Hisham Muhammad's avatar
Hisham Muhammad committed
946
      if (i == 0)
947
         sscanf(buffer, "cpu  %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
Hisham Muhammad's avatar
Hisham Muhammad committed
948
      else {
949
         sscanf(buffer, "cpu%4d %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu %16llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest, &guestnice);
Hisham Muhammad's avatar
Hisham Muhammad committed
950
951
         assert(cpuid == i - 1);
      }
952
953
954
      // Guest time is already accounted in usertime
      usertime = usertime - guest;
      nicetime = nicetime - guestnice;
Hisham Muhammad's avatar
Hisham Muhammad committed
955
956
      // Fields existing on kernels >= 2.6
      // (and RHEL's patched kernel 2.4...)
957
      idlealltime = idletime + ioWait;
958
      systemalltime = systemtime + irq + softIrq;
959
960
      virtalltime = guest + guestnice;
      totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
961
962
963
964
965
966
967
968
969
970
971
972
      CPUData* cpuData = &(this->cpus[i]);
      assert (usertime >= cpuData->userTime);
      assert (nicetime >= cpuData->niceTime);
      assert (systemtime >= cpuData->systemTime);
      assert (idletime >= cpuData->idleTime);
      assert (totaltime >= cpuData->totalTime);
      assert (systemalltime >= cpuData->systemAllTime);
      assert (idlealltime >= cpuData->idleAllTime);
      assert (ioWait >= cpuData->ioWaitTime);
      assert (irq >= cpuData->irqTime);
      assert (softIrq >= cpuData->softIrqTime);
      assert (steal >= cpuData->stealTime);
973
      assert (virtalltime >= cpuData->guestTime);
974
975
976
977
978
979
980
981
982
983
      cpuData->userPeriod = usertime - cpuData->userTime;
      cpuData->nicePeriod = nicetime - cpuData->niceTime;
      cpuData->systemPeriod = systemtime - cpuData->systemTime;
      cpuData->systemAllPeriod = systemalltime - cpuData->systemAllTime;
      cpuData->idleAllPeriod = idlealltime - cpuData->idleAllTime;
      cpuData->idlePeriod = idletime - cpuData->idleTime;
      cpuData->ioWaitPeriod = ioWait - cpuData->ioWaitTime;
      cpuData->irqPeriod = irq - cpuData->irqTime;
      cpuData->softIrqPeriod = softIrq - cpuData->softIrqTime;
      cpuData->stealPeriod = steal - cpuData->stealTime;
984
      cpuData->guestPeriod = virtalltime - cpuData->guestTime;
985
986
987
988
989
990
991
992
993
994
995
      cpuData->totalPeriod = totaltime - cpuData->totalTime;
      cpuData->userTime = usertime;
      cpuData->niceTime = nicetime;
      cpuData->systemTime = systemtime;
      cpuData->systemAllTime = systemalltime;
      cpuData->idleAllTime = idlealltime;
      cpuData->idleTime = idletime;
      cpuData->ioWaitTime = ioWait;
      cpuData->irqTime = irq;
      cpuData->softIrqTime = softIrq;
      cpuData->stealTime = steal;
996
      cpuData->guestTime = virtalltime;
997
      cpuData->totalTime = totaltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
998
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
999
   double period = (double)this->cpus[0].totalPeriod / cpus; fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
1000
1001

   // mark all process as "dirty"
1002
1003
   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
1004
1005
1006
1007
      p->updated = false;
   }
   
   this->totalTasks = 0;
1008
1009
   this->userlandThreads = 0;
   this->kernelThreads = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
1010
   this->runningTasks = 0;
1011

Hisham Muhammad's avatar
Hisham Muhammad committed
1012
1013
1014
   struct timeval tv;
   gettimeofday(&tv, NULL);
   ProcessList_processEntries(this, PROCDIR, NULL, period, tv);
Hisham Muhammad's avatar
Hisham Muhammad committed
1015
1016
   
   this->showingThreadNames = this->showThreadNames;
Hisham Muhammad's avatar
Hisham Muhammad committed
1017
   
1018
1019
   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
1020
1021
1022
1023
1024
1025
1026
      if (p->updated == false)
         ProcessList_remove(this, p);
      else
         p->updated = false;
   }

}
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040

ProcessField ProcessList_keyAt(ProcessList* this, int at) {
   int x = 0;
   ProcessField* fields = this->fields;
   ProcessField field;
   for (int i = 0; (field = fields[i]); i++) {
      int len = strlen(Process_fieldTitles[field]);
      if (at >= x && at <= x + len) {
         return field;
      }
      x += len;
   }
   return COMM;
}
1041
1042
1043
1044
1045
1046
1047
1048

void ProcessList_expandTree(ProcessList* this) {
   int size = Vector_size(this->processes);
   for (int i = 0; i < size; i++) {
      Process* process = (Process*) Vector_get(this->processes, i);
      process->showChildren = true;
   }
}
1049

Hisham Muhammad's avatar
Hisham Muhammad committed
1050
void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, const char* incFilter) {
1051
   if (!flags) {
1052
      following = this->following;
1053
1054
      incFilter = this->incFilter;
   } else {
1055
      this->following = following;
1056
1057
1058
1059
      this->incFilter = incFilter;
   }

   int currPos = Panel_getSelectedIndex(this->panel);
1060
   pid_t currPid = following != -1 ? following : 0;
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
   int currScrollV = this->panel->scrollV;

   Panel_prune(this->panel);
   int size = ProcessList_size(this);
   int idx = 0;
   for (int i = 0; i < size; i++) {
      bool hidden = false;
      Process* p = ProcessList_get(this, i);

      if ( (!p->show)
Hisham Muhammad's avatar
Hisham Muhammad committed
1071
         || (this->userOnly && (p->st_uid != this->userId))
1072
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
1073
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) )
1074
1075
1076
1077
         hidden = true;

      if (!hidden) {
         Panel_set(this->panel, idx, (Object*)p);
1078
         if ((following == -1 && idx == currPos) || (following != -1 && p->pid == currPid)) {
1079
1080
1081
1082
1083
1084
1085
            Panel_setSelected(this->panel, idx);
            this->panel->scrollV = currScrollV;
         }
         idx++;
      }
   }
}