ProcessList.c 32.3 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_ {
102
103
   Vector* processes;
   Vector* processes2;
Hisham Muhammad's avatar
Hisham Muhammad committed
104
105
106
   Hashtable* processTable;
   UsersTable* usersTable;

107
   Panel* panel;
108
   int following;
109
110
111
   bool userOnly;
   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
   const char **treeStr;
Hisham Muhammad's avatar
Hisham Muhammad committed
154
155

} ProcessList;
156

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

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

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
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;
}

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

221
#ifdef HAVE_LIBHWLOC
222
223
224
225
226
227
228
   this->topologyOk = false;
   int topoErr = hwloc_topology_init(&this->topology);
   if (topoErr == 0) {
      topoErr = hwloc_topology_load(this->topology);
      this->topologyOk = true;
   }
#endif
229
   this->cpus = calloc(sizeof(CPUData), cpus);
230

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
430
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
   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
470
471
}

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

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

492
#ifdef HAVE_TASKSTATS
493

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

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

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

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

660
661
#endif

662
663
664
static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
   if (Process_isKernelThread(process))
      return true;
665

666
667
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
668
669
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
670
671
672
      return false;
         
   char command[4096+1]; // max cmdline length on Linux
Hisham Muhammad's avatar
Hisham Muhammad committed
673
674
   int amtRead = xread(fd, command, sizeof(command) - 1);
   close(fd);
675
676
677
678
679
680
681
682
   if (amtRead > 0) {
      for (int i = 0; i < amtRead; i++)
         if (command[i] == '\0' || command[i] == '\n') {
            command[i] = ' ';
         }
   }
   command[amtRead] = '\0';
   free(process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
683
   process->comm = strdup(command);
684

685
686
687
688
   return true;
}


Hisham Muhammad's avatar
Hisham Muhammad committed
689
static bool ProcessList_processEntries(ProcessList* this, const char* dirname, Process* parent, double period, struct timeval tv) {
Hisham Muhammad's avatar
Hisham Muhammad committed
690
691
692
   DIR* dir;
   struct dirent* entry;

Hisham Muhammad's avatar
Hisham Muhammad committed
693
694
695
696
697
   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
698
   dir = opendir(dirname);
699
   if (!dir) return false;
700
   int cpus = this->cpuCount;
701
702
   bool hideKernelThreads = this->hideKernelThreads;
   bool hideUserlandThreads = this->hideUserlandThreads;
Hisham Muhammad's avatar
Hisham Muhammad committed
703
704
   while ((entry = readdir(dir)) != NULL) {
      char* name = entry->d_name;
Hisham Muhammad's avatar
Hisham Muhammad committed
705
706
707
708
709
710
711
712
713
714
715

      // 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
716
      // filename is a number: process directory
717
718
719
      int pid = atoi(name);
     
      if (parent && pid == parent->pid)
720
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
721

722
723
      if (pid <= 0) 
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
724

725
726
727
728
729
730
731
732
733
734
735
      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;
736
         process->tgid = parent ? parent->pid : pid;
737
      }
738

739
740
      char subdirname[MAX_NAME+1];
      snprintf(subdirname, MAX_NAME, "%s/%s/task", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
741
      ProcessList_processEntries(this, subdirname, process, period, tv);
742

743
      #ifdef HAVE_TASKSTATS
744
745
      if (this->flags & PROCESS_FLAG_IO)
         ProcessList_readIoFile(process, dirname, name, now);
746
      #endif
747

748
749
      if (! ProcessList_readStatmFile(process, dirname, name))
         goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
750

751
      process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
752

753
      char command[MAX_NAME+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
754
      unsigned long long int lasttimes = (process->utime + process->stime);
755
756
      if (! ProcessList_readStatFile(process, dirname, name, command))
         goto errorReadingProcess;
757
758
      if (this->flags & PROCESS_FLAG_IOPRIO)
         Process_updateIOPriority(process);
759
      float percent_cpu = (process->utime + process->stime - lasttimes) / period * 100.0;
760
761
      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
762
      process->percent_mem = (process->m_resident * PAGE_SIZE_KB) / (double)(this->totalMem) * 100.0;
763

764
      if(!existingProcess) {
765

Hisham Muhammad's avatar
Hisham Muhammad committed
766
         if (! ProcessList_statProcessDir(process, dirname, name, curTime))
767
768
            goto errorReadingProcess;

769
770
         process->user = UsersTable_getRef(this->usersTable, process->st_uid);

771
         #ifdef HAVE_OPENVZ
772
773
         if (this->flags & PROCESS_FLAG_OPENVZ)
            ProcessList_readOpenVZData(process, dirname, name);
774
         #endif
775

776
         #ifdef HAVE_CGROUP
777
778
         if (this->flags & PROCESS_FLAG_CGROUP)
            ProcessList_readCGroupFile(process, dirname, name);
779
         #endif
780
         
781
         #ifdef HAVE_VSERVER
782
783
         if (this->flags & PROCESS_FLAG_VSERVER)
            ProcessList_readVServerData(process, dirname, name);
784
785
786
         #endif
         
         if (! ProcessList_readCmdlineFile(process, dirname, name))
787
788
            goto errorReadingProcess;

789
         ProcessList_add(this, process);
790
791
792
793
794
      } else {
         if (this->updateProcessNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
         }
795
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
796

797
798
      if (process->state == 'Z') {
         free(process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
799
         process->comm = strdup(command);
800
      } else if (Process_isThread(process)) {
801
         if (this->showThreadNames || Process_isKernelThread(process) || process->state == 'Z') {
802
            free(process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
803
            process->comm = strdup(command);
804
805
806
         } else if (this->showingThreadNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
807
         }
808
809
810
811
812
         if (Process_isKernelThread(process)) {
            this->kernelThreads++;
         } else {
            this->userlandThreads++;
         }
813
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
814

815
816
817
818
      this->totalTasks++;
      if (process->state == 'R')
         this->runningTasks++;
      process->updated = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
819

820
      continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
821

822
823
824
825
826
      // Exception handler.
      errorReadingProcess: {
         if (process->comm) {
            free(process->comm);
            process->comm = NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
827
         }
828
829
830
831
         if (existingProcess)
            ProcessList_remove(this, process);
         else
            Process_delete((Object*)process);
Hisham Muhammad's avatar
Hisham Muhammad committed
832
833
834
      }
   }
   closedir(dir);
835
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
836
837
838
}

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

842
   FILE* file = fopen(PROCMEMINFOFILE, "r");
843
844
845
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCMEMINFOFILE);
   }
846
   int cpus = this->cpuCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
847
848
   {
      char buffer[128];
849
      while (fgets(buffer, 128, file)) {
Hisham Muhammad's avatar
Hisham Muhammad committed
850
851
852
853
   
         switch (buffer[0]) {
         case 'M':
            if (String_startsWith(buffer, "MemTotal:"))
854
               sscanf(buffer, "MemTotal: %llu kB", &this->totalMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
855
            else if (String_startsWith(buffer, "MemFree:"))
856
               sscanf(buffer, "MemFree: %llu kB", &this->freeMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
857
            else if (String_startsWith(buffer, "MemShared:"))
858
               sscanf(buffer, "MemShared: %llu kB", &this->sharedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
859
860
861
            break;
         case 'B':
            if (String_startsWith(buffer, "Buffers:"))
862
               sscanf(buffer, "Buffers: %llu kB", &this->buffersMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
863
864
865
            break;
         case 'C':
            if (String_startsWith(buffer, "Cached:"))
866
               sscanf(buffer, "Cached: %llu kB", &this->cachedMem);
Hisham Muhammad's avatar
Hisham Muhammad committed
867
868
869
            break;
         case 'S':
            if (String_startsWith(buffer, "SwapTotal:"))
870
               sscanf(buffer, "SwapTotal: %llu kB", &this->totalSwap);
Hisham Muhammad's avatar
Hisham Muhammad committed
871
            if (String_startsWith(buffer, "SwapFree:"))
872
               sscanf(buffer, "SwapFree: %llu kB", &swapFree);
Hisham Muhammad's avatar
Hisham Muhammad committed
873
874
            break;
         }
Hisham Muhammad's avatar
Hisham Muhammad committed
875
876
      }
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
877

Hisham Muhammad's avatar
Hisham Muhammad committed
878
879
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
880
   fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
881

882
   file = fopen(PROCSTATFILE, "r");
883
884
885
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCSTATFILE);
   }
886
   for (int i = 0; i <= cpus; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
887
888
      char buffer[256];
      int cpuid;
889
890
      unsigned long long int ioWait, irq, softIrq, steal, guest;
      ioWait = irq = softIrq = steal = guest = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
891
892
893
      // Dependending on your kernel version,
      // 5, 7 or 8 of these fields will be set.
      // The rest will remain at zero.
894
      fgets(buffer, 255, file);
Hisham Muhammad's avatar
Hisham Muhammad committed
895
      if (i == 0)
896
         sscanf(buffer, "cpu  %llu %llu %llu %llu %llu %llu %llu %llu %llu", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest);
Hisham Muhammad's avatar
Hisham Muhammad committed
897
      else {
898
         sscanf(buffer, "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq, &steal, &guest);
Hisham Muhammad's avatar
Hisham Muhammad committed
899
900
901
902
         assert(cpuid == i - 1);
      }
      // Fields existing on kernels >= 2.6
      // (and RHEL's patched kernel 2.4...)
903
      idlealltime = idletime + ioWait;
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
      systemalltime = systemtime + irq + softIrq;
      virtalltime = steal + guest;
      totaltime = usertime + nicetime + systemalltime + idlealltime + virtalltime;
      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);
      assert (guest >= cpuData->guestTime);
      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;
      cpuData->guestPeriod = guest - cpuData->guestTime;
      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;
      cpuData->guestTime = guest;
      cpuData->totalTime = totaltime;
Hisham Muhammad's avatar
Hisham Muhammad committed
944
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
945
   double period = (double)this->cpus[0].totalPeriod / cpus; fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
946
947

   // mark all process as "dirty"
948
949
   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
950
951
952
953
      p->updated = false;
   }
   
   this->totalTasks = 0;
954
955
   this->userlandThreads = 0;
   this->kernelThreads = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
956
   this->runningTasks = 0;
957

Hisham Muhammad's avatar
Hisham Muhammad committed
958
959
960
   struct timeval tv;
   gettimeofday(&tv, NULL);
   ProcessList_processEntries(this, PROCDIR, NULL, period, tv);
Hisham Muhammad's avatar
Hisham Muhammad committed
961
962
   
   this->showingThreadNames = this->showThreadNames;
Hisham Muhammad's avatar
Hisham Muhammad committed
963
   
964
965
   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
966
967
968
969
970
971
972
      if (p->updated == false)
         ProcessList_remove(this, p);
      else
         p->updated = false;
   }

}
973
974
975
976
977
978
979
980
981
982
983
984
985
986

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;
}
987
988
989
990
991
992
993
994

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

996
void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, bool userOnly, uid_t userId, const char* incFilter) {
997
   if (!flags) {
998
      following = this->following;
999
1000
1001
1002
      userOnly = this->userOnly;
      userId = this->userId;
      incFilter = this->incFilter;
   } else {
1003
      this->following = following;
1004
1005
1006
1007
1008
1009
      this->userOnly = userOnly;
      this->userId = userId;
      this->incFilter = incFilter;
   }

   int currPos = Panel_getSelectedIndex(this->panel);
1010
   pid_t currPid = following != -1 ? following : 0;
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
   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))
1022
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
1023
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) )
1024
1025
1026
1027
         hidden = true;

      if (!hidden) {
         Panel_set(this->panel, idx, (Object*)p);
1028
         if ((following == -1 && idx == currPos) || (following != -1 && p->pid == currPid)) {
1029
1030
1031
1032
1033
1034
1035
            Panel_setSelected(this->panel, idx);
            this->panel->scrollV = currScrollV;
         }
         idx++;
      }
   }
}