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->fields[i] |= Process_fieldFlags[defaultHeaders[i]];
Hisham Muhammad's avatar
Hisham Muhammad committed
246
247
248
249
250
   }
   this->sortKey = PERCENT_CPU;
   this->direction = 1;
   this->hideThreads = false;
   this->shadowOtherUsers = false;
251
252
   this->showThreadNames = false;
   this->showingThreadNames = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
253
254
255
256
257
   this->hideKernelThreads = false;
   this->hideUserlandThreads = false;
   this->treeView = false;
   this->highlightBaseName = false;
   this->highlightMegabytes = false;
258
   this->detailedCPUTime = false;
259
   this->countCPUsFromZero = false;
260
   this->updateProcessNames = false;
261
   this->treeStr = NULL;
262
   this->following = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
263

264
265
266
   if (CRT_utf8)
      this->treeStr = CRT_utf8 ? ProcessList_treeStrUtf8 : ProcessList_treeStrAscii;

Hisham Muhammad's avatar
Hisham Muhammad committed
267
268
269
270
271
   return this;
}

void ProcessList_delete(ProcessList* this) {
   Hashtable_delete(this->processTable);
272
273
   Vector_delete(this->processes);
   Vector_delete(this->processes2);
274
   free(this->cpus);
Hisham Muhammad's avatar
Hisham Muhammad committed
275
276
277
278
   free(this->fields);
   free(this);
}

279
280
281
282
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
   this->panel = panel;
}

Hisham Muhammad's avatar
Hisham Muhammad committed
283
284
285
286
287
288
289
void ProcessList_invertSortOrder(ProcessList* this) {
   if (this->direction == 1)
      this->direction = -1;
   else
      this->direction = 1;
}

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

302
static 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
   
306
   Vector_add(this->processes, p);
Hisham Muhammad's avatar
Hisham Muhammad committed
307
   Hashtable_put(this->processTable, p->pid, p);
308
   
309
310
   assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
   assert(Hashtable_get(this->processTable, p->pid) != NULL);
311
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
312
313
}

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

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

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

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

338
   for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
339
      Process* process = (Process*) (Vector_get(this->processes, i));
340
      if (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid)) {
Hisham Muhammad's avatar
Hisham Muhammad committed
341
         process = (Process*) (Vector_take(this->processes, i));
342
         Vector_add(children, process);
Hisham Muhammad's avatar
Hisham Muhammad committed
343
344
      }
   }
345
   int size = Vector_size(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
346
   for (int i = 0; i < size; i++) {
347
      Process* process = (Process*) (Vector_get(children, i));
348
349
350
351
352
353
354
355
356
      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);
357
      ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false);
358
359
360
361
      if (i == size - 1)
         process->indent = -nextIndent;
      else
         process->indent = nextIndent;
Hisham Muhammad's avatar
Hisham Muhammad committed
362
   }
363
   Vector_delete(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
364
365
366
367
}

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

406
407
408
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
409
410
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
411
412
      return false;

Hisham Muhammad's avatar
Hisham Muhammad committed
413
   static char buf[MAX_READ+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
414

Hisham Muhammad's avatar
Hisham Muhammad committed
415
416
   int size = xread(fd, buf, MAX_READ);
   close(fd);
Hisham Muhammad's avatar
Hisham Muhammad committed
417
   if (size <= 0) return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
418
   buf[size] = '\0';
Hisham Muhammad's avatar
Hisham Muhammad committed
419

420
   assert(process->pid == atoi(buf));
Hisham Muhammad's avatar
Hisham Muhammad committed
421
   char *location = strchr(buf, ' ');
Hisham Muhammad's avatar
Hisham Muhammad committed
422
   if (!location) return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
423
424
425

   location += 2;
   char *end = strrchr(location, ')');
Hisham Muhammad's avatar
Hisham Muhammad committed
426
   if (!end) return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
427
428
429
430
431
   
   int commsize = end - location;
   memcpy(command, location, commsize);
   command[commsize] = '\0';
   location = end + 2;
432

Hisham Muhammad's avatar
Hisham Muhammad committed
433
434
435
436
437
438
439
440
441
442
443
444
445
446
   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;
447
448
449
450
451
452
453
454
   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
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
   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
477
478
}

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

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

499
#ifdef HAVE_TASKSTATS
500

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

505
   snprintf(filename, MAX_NAME, "%s/%s/io", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
506
507
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
508
509
      return;
   
Hisham Muhammad's avatar
Hisham Muhammad committed
510
511
512
513
514
   char buffer[1024];
   ssize_t buflen = xread(fd, buffer, 1023);
   close(fd);
   if (buflen < 1) return;
   buffer[buflen] = '\0';
515
516
   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
517
518
519
520
   char *buf = buffer;
   char *line = NULL;
   while ((line = strsep(&buf, "\n")) != NULL) {
      switch (line[0]) {
521
      case 'r':
Hisham Muhammad's avatar
Hisham Muhammad committed
522
523
524
525
         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);
526
527
528
529
530
531
            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
532
533
534
535
         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);
536
537
538
539
540
541
            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
542
543
544
         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)
545
            sscanf(line, "syscw: %32llu", &process->io_syscw);
Hisham Muhammad's avatar
Hisham Muhammad committed
546
            process->io_syscw = strtoull(line+7, NULL, 10);
547
548
         break;
      case 'c':
Hisham Muhammad's avatar
Hisham Muhammad committed
549
550
         if (strncmp(line+1, "ancelled_write_bytes: ", 22) == 0)
           process->io_cancelled_write_bytes = strtoull(line+23, NULL, 10);
551
552
553
554
555
556
557
558
559
      }
   }
}

#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
560
561
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
562
      return false;
Hisham Muhammad's avatar
Hisham Muhammad committed
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
   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);
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
}

#ifdef HAVE_OPENVZ

static void ProcessList_readOpenVZData(Process* process, const char* dirname, const char* name) {
   if (access("/proc/vz", R_OK) != 0) {
      process->vpid = process->pid;
      process->ctid = 0;
      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, 
594
595
596
597
598
599
600
      "%*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",
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
      &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);
621
622
      int nFields;
      char** fields = String_split(trimmed, ':', &nFields);
623
      free(trimmed);
624
625
626
627
628
      if (nFields >= 3) {
         process->cgroup = strndup(fields[2] + 1, 10);
      } else {
         process->cgroup = strdup("");
      }
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
      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;
649
         int ok = sscanf(buffer, "VxID:\t%32d", &vxid);
650
651
         if (ok >= 1) {
            process->vxid = vxid;
652
         }
653
654
655
656
      }
      #if defined HAVE_ANCIENT_VSERVER
      else if (String_startsWith(buffer, "s_context:")) {
         int vxid;
657
         int ok = sscanf(buffer, "s_context:\t%32d", &vxid);
658
659
         if (ok >= 1) {
            process->vxid = vxid;
660
661
         }
      }
662
      #endif
663
   }
664
   fclose(file);
665
}
666

667
668
#endif

669
670
671
672
673
674
675
#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)
676
      return;
677
   char buffer[256];
678
679
   if (fgets(buffer, 255, file)) {
      unsigned int oom;
680
      int ok = sscanf(buffer, "%32u", &oom);
681
682
683
      if (ok >= 1) {
         process->oom = oom;
      }
684
685
686
687
688
689
   }
   fclose(file);
}

#endif

690
691
692
static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
   if (Process_isKernelThread(process))
      return true;
693

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

721
722
723
724
   return true;
}


Hisham Muhammad's avatar
Hisham Muhammad committed
725
static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
Hisham Muhammad's avatar
Hisham Muhammad committed
726
727
728
   DIR* dir;
   struct dirent* entry;

Hisham Muhammad's avatar
Hisham Muhammad committed
729
730
   time_t curTime = tv.tv_sec;
   #ifdef HAVE_TASKSTATS
Hisham Muhammad's avatar
Hisham Muhammad committed
731
   unsigned long long now = tv.tv_sec*1000LL+tv.tv_usec/1000LL;
Hisham Muhammad's avatar
Hisham Muhammad committed
732
733
   #endif

Hisham Muhammad's avatar
Hisham Muhammad committed
734
   dir = opendir(dirname);
735
   if (!dir) return false;
736
   int cpus = this->cpuCount;
737
738
   bool hideKernelThreads = this->hideKernelThreads;
   bool hideUserlandThreads = this->hideUserlandThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
739
740
   while ((entry = readdir(dir)) != NULL) {
      char* name = entry->d_name;
Hisham Muhammad's avatar
Hisham Muhammad committed
741
742
743
744
745
746
747
748

      // 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.
749
      if (name[0] < '0' || name[0] > '9') {
Hisham Muhammad's avatar
Hisham Muhammad committed
750
         continue;
751
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
752

Hisham Muhammad's avatar
Hisham Muhammad committed
753
      // filename is a number: process directory
754
755
756
      int pid = atoi(name);
     
      if (parent && pid == parent->pid)
757
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
758

759
760
      if (pid <= 0) 
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
761

762
763
764
765
766
767
768
769
770
771
772
      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;
773
         process->tgid = parent ? parent->pid : pid;
774
      }
775

776
777
      char subdirname[MAX_NAME+1];
      snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
778
      ProcessList_processEntries(this, subdirname, process, period, tv);
779

780
      #ifdef HAVE_TASKSTATS
781
782
      if (this->flags & PROCESS_FLAG_IO)
         ProcessList_readIoFile(process, dirname, name, now);
783
      #endif
784

785
786
      if (! ProcessList_readStatmFile(process, dirname, name))
         goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
787

788
      process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
789

790
      char command[MAX_NAME+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
791
      unsigned long long int lasttimes = (process->utime + process->stime);
792
793
      if (! ProcessList_readStatFile(process, dirname, name, command))
         goto errorReadingProcess;
794
795
      if (this->flags & PROCESS_FLAG_IOPRIO)
         Process_updateIOPriority(process);
796
      float percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0;
797
798
      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
799
      process->percent_mem = (process->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem) * 100.0;
800

801
      if(!existingProcess) {
802

Hisham Muhammad's avatar
Hisham Muhammad committed
803
         if (! ProcessList_statProcessDir(process, dirname, name, curTime))
804
805
            goto errorReadingProcess;

806
807
         process->user = UsersTable_getRef(this->usersTable, process->st_uid);

808
         #ifdef HAVE_OPENVZ
809
810
         if (this->flags & PROCESS_FLAG_OPENVZ)
            ProcessList_readOpenVZData(process, dirname, name);
811
         #endif
812

813
         #ifdef HAVE_CGROUP
814
815
         if (this->flags & PROCESS_FLAG_CGROUP)
            ProcessList_readCGroupFile(process, dirname, name);
816
         #endif
817
         
818
         #ifdef HAVE_VSERVER
819
820
         if (this->flags & PROCESS_FLAG_VSERVER)
            ProcessList_readVServerData(process, dirname, name);
821
822
         #endif
         
823
824
825
826
         #ifdef HAVE_OOM
         ProcessList_readOomData(process, dirname, name);
         #endif

827
         if (! ProcessList_readCmdlineFile(process, dirname, name))
828
829
            goto errorReadingProcess;

830
         ProcessList_add(this, process);
831
832
833
834
835
      } else {
         if (this->updateProcessNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
         }
836
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
837

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

858
859
860
861
      this->totalTasks++;
      if (process->state == 'R')
         this->runningTasks++;
      process->updated = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
862

863
      continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
864

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
923
924
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
925
   fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
926

927
   file = fopen(PROCSTATFILE, "r");
928
929
930
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCSTATFILE);
   }
931
   for (int i = 0; i <= cpus; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
932
933
      char buffer[256];
      int cpuid;
934
      unsigned long long int ioWait, irq, softIrq, steal, guest, guestnice;
Hisham Muhammad's avatar
Hisham Muhammad committed
935
      unsigned long long int systemalltime, idlealltime, totaltime, virtalltime;
936
      ioWait = irq = softIrq = steal = guest = guestnice = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
937
      // Dependending on your kernel version,
938
      // 5, 7, 8 or 9 of these fields will be set.
Hisham Muhammad's avatar
Hisham Muhammad committed
939
      // The rest will remain at zero.
940
      fgets(buffer, 255, file);
Hisham Muhammad's avatar
Hisham Muhammad committed
941
      if (i == 0)
942
         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
943
      else {
944
         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
945
946
         assert(cpuid == i - 1);
      }
947
948
949
      // Guest time is already accounted in usertime
      usertime = usertime - guest;
      nicetime = nicetime - guestnice;
Hisham Muhammad's avatar
Hisham Muhammad committed
950
951
      // Fields existing on kernels >= 2.6
      // (and RHEL's patched kernel 2.4...)
952
      idlealltime = idletime + ioWait;
953
      systemalltime = systemtime + irq + softIrq;
954
955
      virtalltime = guest + guestnice;
      totaltime = usertime + nicetime + systemalltime + idlealltime + steal + virtalltime;
956
957
958
959
960
961
962
963
964
965
966
967
      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);
968
      assert (virtalltime >= cpuData->guestTime);
969
970
971
972
973
974
975
976
977
978
      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;
979
      cpuData->guestPeriod = virtalltime - cpuData->guestTime;
980
981
982
983
984
985
986
987
988
989
990
      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;
991
      cpuData->guestTime = virtalltime;
992
      cpuData->totalTime = totaltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
993
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
994
   double period = (double)this->cpus[0].totalPeriod / cpus; fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
995
996

   // mark all process as "dirty"
997
998
   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
999
1000
1001
1002
      p->updated = false;
   }
   
   this->totalTasks = 0;
1003
1004
   this->userlandThreads = 0;
   this->kernelThreads = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
1005
   this->runningTasks = 0;
1006

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

}
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035

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;
}
1036
1037
1038
1039
1040
1041
1042
1043

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;
   }
}
1044

1045
void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, bool userOnly, uid_t userId, const char* incFilter) {
1046
   if (!flags) {
1047
      following = this->following;
1048
1049
1050
1051
      userOnly = this->userOnly;
      userId = this->userId;
      incFilter = this->incFilter;
   } else {
1052
      this->following = following;
1053
1054
1055
1056
1057
1058
      this->userOnly = userOnly;
      this->userId = userId;
      this->incFilter = incFilter;
   }

   int currPos = Panel_getSelectedIndex(this->panel);
1059
   pid_t currPid = following != -1 ? following : 0;
1060
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)
         || (userOnly && (p->st_uid != userId))
1071
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
1072
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) )
1073
1074
1075
1076
         hidden = true;

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