ProcessList.c 10.8 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"
9
#include "Platform.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
10
11

#include "CRT.h"
David Hunt's avatar
David Hunt committed
12
#include "StringUtils.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
13
14

#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
15
#include <string.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
16
17

/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
18
19
20
21
22
#include "Vector.h"
#include "Hashtable.h"
#include "UsersTable.h"
#include "Panel.h"
#include "Process.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
23
#include "Settings.h"
24

Hisham's avatar
Hisham committed
25
26
27
28
#ifdef HAVE_LIBHWLOC
#include <hwloc.h>
#endif

Hisham Muhammad's avatar
Hisham Muhammad committed
29
#ifndef MAX_NAME
Hisham Muhammad's avatar
Hisham Muhammad committed
30
31
32
33
#define MAX_NAME 128
#endif

#ifndef MAX_READ
34
#define MAX_READ 2048
Hisham Muhammad's avatar
Hisham Muhammad committed
35
36
37
#endif

typedef struct ProcessList_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
38
39
   Settings* settings;

40
41
   Vector* processes;
   Vector* processes2;
Hisham Muhammad's avatar
Hisham Muhammad committed
42
43
44
   Hashtable* processTable;
   UsersTable* usersTable;

45
   Panel* panel;
46
   int following;
47
48
   uid_t userId;
   const char* incFilter;
49
   Hashtable* pidWhiteList;
50

51
   #ifdef HAVE_LIBHWLOC
52
53
54
   hwloc_topology_t topology;
   bool topologyOk;
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
55

56
57
58
59
60
   int totalTasks;
   int runningTasks;
   int userlandThreads;
   int kernelThreads;

61
62
63
64
65
66
67
68
69
70
   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
71
   int cpuCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
72
73

} ProcessList;
74

Hisham Muhammad's avatar
Hisham Muhammad committed
75
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
76
void ProcessList_delete(ProcessList* pl);
77
void ProcessList_goThroughEntries(ProcessList* pl);
78

Hisham Muhammad's avatar
Hisham Muhammad committed
79
80
}*/

81
82
ProcessList* ProcessList_init(ProcessList* this, ObjectClass* klass, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
   this->processes = Vector_new(klass, true, DEFAULT_SIZE);
83
   this->processTable = Hashtable_new(140, false);
Hisham Muhammad's avatar
Hisham Muhammad committed
84
   this->usersTable = usersTable;
85
   this->pidWhiteList = pidWhiteList;
Hisham Muhammad's avatar
Hisham Muhammad committed
86
   this->userId = userId;
Hisham Muhammad's avatar
Hisham Muhammad committed
87
   
88
89
   // tree-view auxiliary buffer
   this->processes2 = Vector_new(klass, true, DEFAULT_SIZE);
Hisham Muhammad's avatar
Hisham Muhammad committed
90
   
91
92
   // set later by platform-specific code
   this->cpuCount = 0;
93

94
#ifdef HAVE_LIBHWLOC
95
96
97
98
   this->topologyOk = false;
   int topoErr = hwloc_topology_init(&this->topology);
   if (topoErr == 0) {
      topoErr = hwloc_topology_load(this->topology);
Hisham Muhammad's avatar
Hisham Muhammad committed
99
100
   }
   if (topoErr == 0) {
101
102
103
      this->topologyOk = true;
   }
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
104

105
   this->following = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
106
107
108
109

   return this;
}

110
void ProcessList_done(ProcessList* this) {
Hisham's avatar
Hisham committed
111
112
113
114
115
#ifdef HAVE_LIBHWLOC
   if (this->topologyOk) {
      hwloc_topology_destroy(this->topology);
   }
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
116
   Hashtable_delete(this->processTable);
117
118
   Vector_delete(this->processes);
   Vector_delete(this->processes2);
Hisham Muhammad's avatar
Hisham Muhammad committed
119
120
}

121
122
123
124
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
   this->panel = panel;
}

125
126
void ProcessList_printHeader(ProcessList* this, RichString* header) {
   RichString_prune(header);
Hisham Muhammad's avatar
Hisham Muhammad committed
127
   ProcessField* fields = this->settings->fields;
Hisham Muhammad's avatar
Hisham Muhammad committed
128
   for (int i = 0; fields[i]; i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
129
130
131
      const char* field = Process_fields[fields[i]].title;
      if (!field) field = "- ";
      if (!this->settings->treeView && this->settings->sortKey == fields[i])
132
         RichString_append(header, CRT_colors[PANEL_SELECTION_FOCUS], field);
Hisham Muhammad's avatar
Hisham Muhammad committed
133
      else
134
         RichString_append(header, CRT_colors[PANEL_HEADER_FOCUS], field);
Hisham Muhammad's avatar
Hisham Muhammad committed
135
136
137
   }
}

138
void ProcessList_add(ProcessList* this, Process* p) {
139
140
   assert(Vector_indexOf(this->processes, p, Process_pidCompare) == -1);
   assert(Hashtable_get(this->processTable, p->pid) == NULL);
141
   
142
   Vector_add(this->processes, p);
Hisham Muhammad's avatar
Hisham Muhammad committed
143
   Hashtable_put(this->processTable, p->pid, p);
144
   
145
146
   assert(Vector_indexOf(this->processes, p, Process_pidCompare) != -1);
   assert(Hashtable_get(this->processTable, p->pid) != NULL);
147
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
148
149
}

150
void ProcessList_remove(ProcessList* this, Process* p) {
151
152
153
   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);
154
   assert(pp == p); (void)pp;
155
   unsigned int pid = p->pid;
Hisham Muhammad's avatar
Hisham Muhammad committed
156
157
158
   int idx = Vector_indexOf(this->processes, p, Process_pidCompare);
   assert(idx != -1);
   if (idx >= 0) Vector_remove(this->processes, idx);
159
   assert(Hashtable_get(this->processTable, pid) == NULL); (void)pid;
160
   assert(Hashtable_count(this->processTable) == Vector_count(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
161
162
}

Hisham Muhammad's avatar
Hisham Muhammad committed
163
164
Process* ProcessList_get(ProcessList* this, int idx) {
   return (Process*) (Vector_get(this->processes, idx));
Hisham Muhammad's avatar
Hisham Muhammad committed
165
166
167
}

int ProcessList_size(ProcessList* this) {
168
   return (Vector_size(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
169
170
}

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

174
   for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
175
      Process* process = (Process*) (Vector_get(this->processes, i));
176
      if (process->show && (process->tgid == pid || (process->tgid == process->pid && process->ppid == pid))) {
Hisham Muhammad's avatar
Hisham Muhammad committed
177
         process = (Process*) (Vector_take(this->processes, i));
178
         Vector_add(children, process);
Hisham Muhammad's avatar
Hisham Muhammad committed
179
180
      }
   }
181
   int size = Vector_size(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
182
   for (int i = 0; i < size; i++) {
183
      Process* process = (Process*) (Vector_get(children, i));
184
185
186
187
188
189
190
191
192
      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);
193
      ProcessList_buildTree(this, process->pid, level+1, (i < size - 1) ? nextIndent : indent, direction, show ? process->showChildren : false);
194
195
196
197
      if (i == size - 1)
         process->indent = -nextIndent;
      else
         process->indent = nextIndent;
Hisham Muhammad's avatar
Hisham Muhammad committed
198
   }
199
   Vector_delete(children);
Hisham Muhammad's avatar
Hisham Muhammad committed
200
201
202
}

void ProcessList_sort(ProcessList* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
203
   if (!this->settings->treeView) {
204
      Vector_insertionSort(this->processes);
Hisham Muhammad's avatar
Hisham Muhammad committed
205
   } else {
206
      // Save settings
Hisham Muhammad's avatar
Hisham Muhammad committed
207
208
      int direction = this->settings->direction;
      int sortKey = this->settings->sortKey;
209
      // Sort by PID
Hisham Muhammad's avatar
Hisham Muhammad committed
210
211
      this->settings->sortKey = PID;
      this->settings->direction = 1;
212
      Vector_quickSort(this->processes);
213
      // Restore settings
Hisham Muhammad's avatar
Hisham Muhammad committed
214
215
      this->settings->sortKey = sortKey;
      this->settings->direction = direction;
216
      int vsize = Vector_size(this->processes);
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
      // Find all processes whose parent is not visible
      int size;
      while ((size = Vector_size(this->processes))) {
         int i;
         for (i = 0; i < size; i++) {
            Process* process = (Process*)(Vector_get(this->processes, i));
            // Immediately consume not shown processes
            if (!process->show) {
               process = (Process*)(Vector_take(this->processes, i));
               process->indent = 0;
               Vector_add(this->processes2, process);
               ProcessList_buildTree(this, process->pid, 0, 0, direction, false);
               break;
            }
            pid_t ppid = process->tgid == process->pid ? process->ppid : process->tgid;
            // Bisect the process vector to find parent
            int l = 0, r = size;
            while (l < r) {
               int c = (l + r) / 2;
               pid_t pid = ((Process*)(Vector_get(this->processes, c)))->pid;
               if (ppid == pid)
                  break;
               else if (ppid < pid)
                  r = c;
               else
                  l = c + 1;
            }
            // If parent not found, then construct the tree with this root
            if (l >= r) {
               process = (Process*)(Vector_take(this->processes, i));
               process->indent = 0;
               Vector_add(this->processes2, process);
               ProcessList_buildTree(this, process->pid, 0, 0, direction, process->showChildren);
               break;
            }
         }
         // There should be no loop in the process tree
         assert(i < size);
255
256
257
      }
      assert(Vector_size(this->processes2) == vsize); (void)vsize;
      assert(Vector_size(this->processes) == 0);
258
      // Swap listings around
259
      Vector* t = this->processes;
Hisham Muhammad's avatar
Hisham Muhammad committed
260
261
262
263
264
      this->processes = this->processes2;
      this->processes2 = t;
   }
}

265
266
267

ProcessField ProcessList_keyAt(ProcessList* this, int at) {
   int x = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
268
   ProcessField* fields = this->settings->fields;
269
270
   ProcessField field;
   for (int i = 0; (field = fields[i]); i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
271
272
273
      const char* title = Process_fields[field].title;
      if (!title) title = "- ";
      int len = strlen(title);
274
275
276
277
278
279
280
      if (at >= x && at <= x + len) {
         return field;
      }
      x += len;
   }
   return COMM;
}
281
282
283
284
285
286
287
288

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

Hisham Muhammad's avatar
Hisham Muhammad committed
290
291
void ProcessList_rebuildPanel(ProcessList* this) {
   const char* incFilter = this->incFilter;
292
293

   int currPos = Panel_getSelectedIndex(this->panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
294
   pid_t currPid = this->following != -1 ? this->following : 0;
295
296
297
298
299
300
301
302
303
304
   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)
Hisham Muhammad's avatar
Hisham Muhammad committed
305
         || (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
306
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
307
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->tgid)) )
308
309
310
311
         hidden = true;

      if (!hidden) {
         Panel_set(this->panel, idx, (Object*)p);
Hisham Muhammad's avatar
Hisham Muhammad committed
312
         if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == currPid)) {
313
314
315
316
317
318
319
            Panel_setSelected(this->panel, idx);
            this->panel->scrollV = currScrollV;
         }
         idx++;
      }
   }
}
320

321
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor) {
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
   Process* proc = (Process*) Hashtable_get(this->processTable, pid);
   *preExisting = proc;
   if (proc) {
      assert(Vector_indexOf(this->processes, proc, Process_pidCompare) != -1);
      assert(proc->pid == pid);
   } else {
      proc = constructor(this->settings);
      assert(proc->comm == NULL);
      proc->pid = pid;
   }
   return proc;
}

void ProcessList_scan(ProcessList* this) {

   // mark all process as "dirty"
   for (int i = 0; i < Vector_size(this->processes); i++) {
      Process* p = (Process*) Vector_get(this->processes, i);
      p->updated = false;
341
      p->show = true;
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
   }

   this->totalTasks = 0;
   this->userlandThreads = 0;
   this->kernelThreads = 0;
   this->runningTasks = 0;

   ProcessList_goThroughEntries(this);
   
   for (int i = Vector_size(this->processes) - 1; i >= 0; i--) {
      Process* p = (Process*) Vector_get(this->processes, i);
      if (p->updated == false)
         ProcessList_remove(this, p);
      else
         p->updated = false;
   }
}