ProcessList.c 33.5 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);
220
   this->cpuCount = cpus - 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
417
418
   int size = xread(fd, buf, MAX_READ);
   close(fd);
   if (!size) return false;
   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
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
   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;
   location = strchr(location, ' ')+1;
   location = strchr(location, ' ')+1;
   location = strchr(location, ' ')+1;
   location = strchr(location, ' ')+1;
   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
473
474
}

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

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

495
#ifdef HAVE_TASKSTATS
496

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

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

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

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

663
664
#endif

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

#endif

686
687
688
static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
   if (Process_isKernelThread(process))
      return true;
689

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

717
718
719
720
   return true;
}


Hisham Muhammad's avatar
Hisham Muhammad committed
721
static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
Hisham Muhammad's avatar
Hisham Muhammad committed
722
723
724
   DIR* dir;
   struct dirent* entry;

Hisham Muhammad's avatar
Hisham Muhammad committed
725
726
727
728
729
   time_t curTime = tv.tv_sec;
   #ifdef HAVE_TASKSTATS
   unsigned long long now = tv.tv_sec*1000+tv.tv_usec/1000;
   #endif

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

      // 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.
745
      if (name[0] < '0' || name[0] > '9') {
Hisham Muhammad's avatar
Hisham Muhammad committed
746
         continue;
747
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
748

Hisham Muhammad's avatar
Hisham Muhammad committed
749
      // filename is a number: process directory
750
751
752
      int pid = atoi(name);
     
      if (parent && pid == parent->pid)
753
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
754

755
756
      if (pid <= 0) 
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
757

758
759
760
761
762
763
764
765
766
767
768
      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;
769
         process->tgid = parent ? parent->pid : pid;
770
      }
771

772
773
      char subdirname[MAX_NAME+1];
      snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
774
      ProcessList_processEntries(this, subdirname, process, period, tv);
775

776
      #ifdef HAVE_TASKSTATS
777
778
      if (this->flags & PROCESS_FLAG_IO)
         ProcessList_readIoFile(process, dirname, name, now);
779
      #endif
780

781
782
      if (! ProcessList_readStatmFile(process, dirname, name))
         goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
783

784
      process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
785

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

797
      if(!existingProcess) {
798

Hisham Muhammad's avatar
Hisham Muhammad committed
799
         if (! ProcessList_statProcessDir(process, dirname, name, curTime))
800
801
            goto errorReadingProcess;

802
803
         process->user = UsersTable_getRef(this->usersTable, process->st_uid);

804
         #ifdef HAVE_OPENVZ
805
806
         if (this->flags & PROCESS_FLAG_OPENVZ)
            ProcessList_readOpenVZData(process, dirname, name);
807
         #endif
808

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

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

854
855
856
857
      this->totalTasks++;
      if (process->state == 'R')
         this->runningTasks++;
      process->updated = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
858

859
      continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
860

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
918
919
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
920
   fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
921

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

   // mark all process as "dirty"
992
993
   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
994
995
996
997
      p->updated = false;
   }
   
   this->totalTasks = 0;
998
999
   this->userlandThreads = 0;
   this->kernelThreads = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
1000
   this->runningTasks = 0;
1001

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

}
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030

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;
}
1031
1032
1033
1034
1035
1036
1037
1038

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

1040
void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, bool userOnly, uid_t userId, const char* incFilter) {
1041
   if (!flags) {
1042
      following = this->following;
1043
1044
1045
1046
      userOnly = this->userOnly;
      userId = this->userId;
      incFilter = this->incFilter;
   } else {
1047
      this->following = following;
1048
1049
1050
1051
1052
1053
      this->userOnly = userOnly;
      this->userId = userId;
      this->incFilter = incFilter;
   }

   int currPos = Panel_getSelectedIndex(this->panel);
1054
   pid_t currPid = following != -1 ? following : 0;
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
   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))
1066
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
1067
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) )
1068
1069
1070
1071
         hidden = true;

      if (!hidden) {
         Panel_set(this->panel, idx, (Object*)p);
1072
         if ((following == -1 && idx == currPos) || (following != -1 && p->pid == currPid)) {
1073
1074
1075
1076
1077
1078
1079
            Panel_setSelected(this->panel, idx);
            this->panel->scrollV = currScrollV;
         }
         idx++;
      }
   }
}