ProcessList.c 9.87 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 Muhammad's avatar
Hisham Muhammad committed
111
   Hashtable_delete(this->processTable);
112
113
   Vector_delete(this->processes);
   Vector_delete(this->processes2);
Hisham Muhammad's avatar
Hisham Muhammad committed
114
115
}

116
117
118
119
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
   this->panel = panel;
}

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
158
159
Process* ProcessList_get(ProcessList* this, int idx) {
   return (Process*) (Vector_get(this->processes, idx));
Hisham Muhammad's avatar
Hisham Muhammad committed
160
161
162
}

int ProcessList_size(ProcessList* this) {
163
   return (Vector_size(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
164
165
}

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

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

void ProcessList_sort(ProcessList* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
198
   if (!this->settings->treeView) {
199
      Vector_insertionSort(this->processes);
Hisham Muhammad's avatar
Hisham Muhammad committed
200
   } else {
201
      // Save settings
Hisham Muhammad's avatar
Hisham Muhammad committed
202
203
      int direction = this->settings->direction;
      int sortKey = this->settings->sortKey;
204
      // Sort by PID
Hisham Muhammad's avatar
Hisham Muhammad committed
205
206
      this->settings->sortKey = PID;
      this->settings->direction = 1;
207
      Vector_quickSort(this->processes);
208
      // Restore settings
Hisham Muhammad's avatar
Hisham Muhammad committed
209
210
      this->settings->sortKey = sortKey;
      this->settings->direction = direction;
211
      // Take PID 1 as root and add to the new listing
212
      int vsize = Vector_size(this->processes);
213
      Process* init = (Process*) (Vector_take(this->processes, 0));
214
      if (!init) return;
215
216
217
      // 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
218
      init->indent = 0;
219
      Vector_add(this->processes2, init);
220
      // Recursively empty list
Hisham Muhammad's avatar
Hisham Muhammad committed
221
      ProcessList_buildTree(this, init->pid, 0, 0, direction, true);
222
      // Add leftovers
223
224
225
226
      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
227
         ProcessList_buildTree(this, p->pid, 0, 0, direction, p->showChildren);
228
229
230
      }
      assert(Vector_size(this->processes2) == vsize); (void)vsize;
      assert(Vector_size(this->processes) == 0);
231
      // Swap listings around
232
      Vector* t = this->processes;
Hisham Muhammad's avatar
Hisham Muhammad committed
233
234
235
236
237
      this->processes = this->processes2;
      this->processes2 = t;
   }
}

238
239
240

ProcessField ProcessList_keyAt(ProcessList* this, int at) {
   int x = 0;
Hisham Muhammad's avatar
Hisham Muhammad committed
241
   ProcessField* fields = this->settings->fields;
242
243
   ProcessField field;
   for (int i = 0; (field = fields[i]); i++) {
Hisham Muhammad's avatar
Hisham Muhammad committed
244
245
246
      const char* title = Process_fields[field].title;
      if (!title) title = "- ";
      int len = strlen(title);
247
248
249
250
251
252
253
      if (at >= x && at <= x + len) {
         return field;
      }
      x += len;
   }
   return COMM;
}
254
255
256
257
258
259
260
261

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

Hisham Muhammad's avatar
Hisham Muhammad committed
263
264
void ProcessList_rebuildPanel(ProcessList* this) {
   const char* incFilter = this->incFilter;
265
266

   int currPos = Panel_getSelectedIndex(this->panel);
Hisham Muhammad's avatar
Hisham Muhammad committed
267
   pid_t currPid = this->following != -1 ? this->following : 0;
268
269
270
271
272
273
274
275
276
277
   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
278
         || (this->userId != (uid_t) -1 && (p->st_uid != this->userId))
279
         || (incFilter && !(String_contains_i(p->comm, incFilter)))
280
         || (this->pidWhiteList && !Hashtable_get(this->pidWhiteList, p->tgid)) )
281
282
283
284
         hidden = true;

      if (!hidden) {
         Panel_set(this->panel, idx, (Object*)p);
Hisham Muhammad's avatar
Hisham Muhammad committed
285
         if ((this->following == -1 && idx == currPos) || (this->following != -1 && p->pid == currPid)) {
286
287
288
289
290
291
292
            Panel_setSelected(this->panel, idx);
            this->panel->scrollV = currScrollV;
         }
         idx++;
      }
   }
}
293

294
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_New constructor) {
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
   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;
   }

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