ProcessList.c 33.4 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
185
186
187
188
189
190
191
192
193
194
195
196
197
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;
  start:;
  ssize_t res = read(fd, buf, count);
  if (res == -1 && errno == EINTR) goto start;
  if (res > 0) {
    buf = ((char*)buf)+res;
    count -= res;
    alreadyRead += res;
  }
  if (res == -1) return -1;
  if (count == 0 || res == 0) return alreadyRead;
  goto start;
}

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
227
228
229
   this->topologyOk = false;
   int topoErr = hwloc_topology_init(&this->topology);
   if (topoErr == 0) {
      topoErr = hwloc_topology_load(this->topology);
      this->topologyOk = true;
   }
#endif
230
   this->cpus = calloc(cpus, sizeof(CPUData));
231

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

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

262
263
264
   if (CRT_utf8)
      this->treeStr = CRT_utf8 ? ProcessList_treeStrUtf8 : ProcessList_treeStrAscii;

Hisham Muhammad's avatar
Hisham Muhammad committed
265
266
267
268
269
   return this;
}

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

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

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

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

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

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

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

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

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

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
411
   static char buf[MAX_READ+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
412

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
431
432
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
   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
471
472
}

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

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

493
#ifdef HAVE_TASKSTATS
494

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

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

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

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

661
662
#endif

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

#endif

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

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

716
717
718
719
   return true;
}


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

Hisham Muhammad's avatar
Hisham Muhammad committed
724
725
726
727
728
   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
729
   dir = opendir(dirname);
730
   if (!dir) return false;
731
   int cpus = this->cpuCount;
732
733
   bool hideKernelThreads = this->hideKernelThreads;
   bool hideUserlandThreads = this->hideUserlandThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
734
735
   while ((entry = readdir(dir)) != NULL) {
      char* name = entry->d_name;
Hisham Muhammad's avatar
Hisham Muhammad committed
736
737
738
739
740
741
742
743
744
745
746

      // 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.
      if (name[0] <= '0' || name[0] >= '9')
         continue;

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

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

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

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

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

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

782
      process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
783

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

795
      if(!existingProcess) {
796

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

800
801
         process->user = UsersTable_getRef(this->usersTable, process->st_uid);

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

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

821
         if (! ProcessList_readCmdlineFile(process, dirname, name))
822
823
            goto errorReadingProcess;

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

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

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

857
      continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
858

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

void ProcessList_scan(ProcessList* this) {
877
   unsigned long long int usertime, nicetime, systemtime, systemalltime, idlealltime, idletime, totaltime, virtalltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
878
   unsigned long long int swapFree = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
879

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

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

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

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

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

}
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027

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;
}
1028
1029
1030
1031
1032
1033
1034
1035

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

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

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

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