ProcessList.c 31.9 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
137
138
139
140

   ProcessField* fields;
   ProcessField sortKey;
   int direction;
   bool hideThreads;
   bool shadowOtherUsers;
Hisham Muhammad's avatar
Hisham Muhammad committed
141
142
   bool showThreadNames;
   bool showingThreadNames;
Hisham Muhammad's avatar
Hisham Muhammad committed
143
144
145
146
147
   bool hideKernelThreads;
   bool hideUserlandThreads;
   bool treeView;
   bool highlightBaseName;
   bool highlightMegabytes;
148
   bool highlightThreads;
149
   bool detailedCPUTime;
150
   bool countCPUsFromZero;
151
   bool updateProcessNames;
152
   const char **treeStr;
Hisham Muhammad's avatar
Hisham Muhammad committed
153
154

} ProcessList;
155

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

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

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

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

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

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

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

258
259
260
   if (CRT_utf8)
      this->treeStr = CRT_utf8 ? ProcessList_treeStrUtf8 : ProcessList_treeStrAscii;

Hisham Muhammad's avatar
Hisham Muhammad committed
261
262
263
264
265
   return this;
}

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

273
274
275
276
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
   this->panel = panel;
}

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

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

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

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

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

int ProcessList_size(ProcessList* this) {
326
   return (Vector_size(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
327
328
}

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

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
407
   static char buf[MAX_READ+1];
Hisham Muhammad's avatar
Hisham Muhammad committed
408

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
427
428
429
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
   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
467
468
}

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

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

489
#ifdef HAVE_TASKSTATS
490

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

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

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

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

657
658
#endif

659
660
661
static bool ProcessList_readCmdlineFile(Process* process, const char* dirname, const char* name) {
   if (Process_isKernelThread(process))
      return true;
662

663
664
   char filename[MAX_NAME+1];
   snprintf(filename, MAX_NAME, "%s/%s/cmdline", dirname, name);
Hisham Muhammad's avatar
Hisham Muhammad committed
665
666
   int fd = open(filename, O_RDONLY);
   if (fd == -1)
667
668
669
      return false;
         
   char command[4096+1]; // max cmdline length on Linux
Hisham Muhammad's avatar
Hisham Muhammad committed
670
671
   int amtRead = xread(fd, command, sizeof(command) - 1);
   close(fd);
672
673
674
675
676
677
678
679
   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
680
   process->comm = strdup(command);
681

682
683
684
685
   return true;
}


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

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

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

719
720
      if (pid <= 0) 
         continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
721

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

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

740
      #ifdef HAVE_TASKSTATS
Hisham Muhammad's avatar
Hisham Muhammad committed
741
      ProcessList_readIoFile(process, dirname, name, now);
742
      #endif
743

744
745
      if (! ProcessList_readStatmFile(process, dirname, name))
         goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
746

747
      process->show = ! ((hideKernelThreads && Process_isKernelThread(process)) || (hideUserlandThreads && Process_isUserlandThread(process)));
748

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

759
      if(!existingProcess) {
760

Hisham Muhammad's avatar
Hisham Muhammad committed
761
         if (! ProcessList_statProcessDir(process, dirname, name, curTime))
762
763
            goto errorReadingProcess;

764
765
         process->user = UsersTable_getRef(this->usersTable, process->st_uid);

766
767
768
         #ifdef HAVE_OPENVZ
         ProcessList_readOpenVZData(process, dirname, name);
         #endif
769

770
771
772
         #ifdef HAVE_CGROUP
         ProcessList_readCGroupFile(process, dirname, name);
         #endif
773
         
774
775
776
777
778
         #ifdef HAVE_VSERVER
         ProcessList_readVServerData(process, dirname, name);
         #endif
         
         if (! ProcessList_readCmdlineFile(process, dirname, name))
779
780
            goto errorReadingProcess;

781
         ProcessList_add(this, process);
782
783
784
785
786
      } else {
         if (this->updateProcessNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
         }
787
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
788

789
790
      if (process->state == 'Z') {
         free(process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
791
         process->comm = strdup(command);
792
      } else if (Process_isThread(process)) {
793
         if (this->showThreadNames || Process_isKernelThread(process) || process->state == 'Z') {
794
            free(process->comm);
Hisham Muhammad's avatar
Hisham Muhammad committed
795
            process->comm = strdup(command);
796
797
798
         } else if (this->showingThreadNames) {
            if (! ProcessList_readCmdlineFile(process, dirname, name))
               goto errorReadingProcess;
Hisham Muhammad's avatar
Hisham Muhammad committed
799
         }
800
801
802
803
804
         if (Process_isKernelThread(process)) {
            this->kernelThreads++;
         } else {
            this->userlandThreads++;
         }
805
      }
Hisham Muhammad's avatar
Hisham Muhammad committed
806

807
808
809
810
      this->totalTasks++;
      if (process->state == 'R')
         this->runningTasks++;
      process->updated = true;
Hisham Muhammad's avatar
Hisham Muhammad committed
811

812
      continue;
Hisham Muhammad's avatar
Hisham Muhammad committed
813

814
815
816
817
818
      // Exception handler.
      errorReadingProcess: {
         if (process->comm) {
            free(process->comm);
            process->comm = NULL;
Hisham Muhammad's avatar
Hisham Muhammad committed
819
         }
820
821
822
823
         if (existingProcess)
            ProcessList_remove(this, process);
         else
            Process_delete((Object*)process);
Hisham Muhammad's avatar
Hisham Muhammad committed
824
825
826
      }
   }
   closedir(dir);
827
   return true;
Hisham Muhammad's avatar
Hisham Muhammad committed
828
829
830
}

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
870
871
   this->usedMem = this->totalMem - this->freeMem;
   this->usedSwap = this->totalSwap - swapFree;
872
   fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
873

874
   file = fopen(PROCSTATFILE, "r");
875
876
877
   if (file == NULL) {
      CRT_fatalError("Cannot open " PROCSTATFILE);
   }
878
   for (int i = 0; i <= cpus; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
879
880
      char buffer[256];
      int cpuid;
881
882
      unsigned long long int ioWait, irq, softIrq, steal, guest;
      ioWait = irq = softIrq = steal = guest = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
883
884
885
      // Dependending on your kernel version,
      // 5, 7 or 8 of these fields will be set.
      // The rest will remain at zero.
886
      fgets(buffer, 255, file);
Hisham Muhammad's avatar
Hisham Muhammad committed
887
      if (i == 0)
888
         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
889
      else {
890
         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
891
892
893
894
         assert(cpuid == i - 1);
      }
      // Fields existing on kernels >= 2.6
      // (and RHEL's patched kernel 2.4...)
895
      idlealltime = idletime + ioWait;
896
897
898
899
900
901
902
903
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
      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
936
   }
Hisham Muhammad's avatar
Hisham Muhammad committed
937
   double period = (double)this->cpus[0].totalPeriod / cpus; fclose(file);
Hisham Muhammad's avatar
Hisham Muhammad committed
938
939

   // mark all process as "dirty"
940
941
   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
942
943
944
945
      p->updated = false;
   }
   
   this->totalTasks = 0;
946
947
   this->userlandThreads = 0;
   this->kernelThreads = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
948
   this->runningTasks = 0;
949

Hisham Muhammad's avatar
Hisham Muhammad committed
950
951
952
   struct timeval tv;
   gettimeofday(&tv, NULL);
   ProcessList_processEntries(this, PROCDIR, NULL, period, tv);
Hisham Muhammad's avatar
Hisham Muhammad committed
953
954
   
   this->showingThreadNames = this->showThreadNames;
Hisham Muhammad's avatar
Hisham Muhammad committed
955
   
956
957
   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
958
959
960
961
962
963
964
      if (p->updated == false)
         ProcessList_remove(this, p);
      else
         p->updated = false;
   }

}
965
966
967
968
969
970
971
972
973
974
975
976
977
978

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;
}
979
980
981
982
983
984
985
986

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

988
void ProcessList_rebuildPanel(ProcessList* this, bool flags, int following, bool userOnly, uid_t userId, const char* incFilter) {
989
   if (!flags) {
990
      following = this->following;
991
992
993
994
      userOnly = this->userOnly;
      userId = this->userId;
      incFilter = this->incFilter;
   } else {
995
      this->following = following;
996
997
998
999
1000
1001
      this->userOnly = userOnly;
      this->userId = userId;
      this->incFilter = incFilter;
   }

   int currPos = Panel_getSelectedIndex(this->panel);
1002
   pid_t currPid = following != -1 ? following : 0;
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
   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))
1014
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
1015
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->pid)) )
1016
1017
1018
1019
         hidden = true;

      if (!hidden) {
         Panel_set(this->panel, idx, (Object*)p);
1020
         if ((following == -1 && idx == currPos) || (following != -1 && p->pid == currPid)) {
1021
1022
1023
1024
1025
1026
1027
            Panel_setSelected(this->panel, idx);
            this->panel->scrollV = currScrollV;
         }
         idx++;
      }
   }
}