ProcessList.c 9.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"
12
#include "String.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 Muhammad's avatar
Hisham Muhammad committed
25
#ifndef MAX_NAME
Hisham Muhammad's avatar
Hisham Muhammad committed
26
27
28
29
#define MAX_NAME 128
#endif

#ifndef MAX_READ
30
#define MAX_READ 2048
Hisham Muhammad's avatar
Hisham Muhammad committed
31
32
33
#endif

typedef struct ProcessList_ {
Hisham Muhammad's avatar
Hisham Muhammad committed
34
35
   Settings* settings;

36
37
   Vector* processes;
   Vector* processes2;
Hisham Muhammad's avatar
Hisham Muhammad committed
38
39
40
   Hashtable* processTable;
   UsersTable* usersTable;

41
   Panel* panel;
42
   int following;
43
44
   uid_t userId;
   const char* incFilter;
45
   Hashtable* pidWhiteList;
46

47
   #ifdef HAVE_LIBHWLOC
48
49
50
   hwloc_topology_t topology;
   bool topologyOk;
   #endif
Hisham Muhammad's avatar
Hisham Muhammad committed
51

52
53
54
55
56
   int totalTasks;
   int runningTasks;
   int userlandThreads;
   int kernelThreads;

57
58
59
60
61
62
63
64
65
66
   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
67
   int cpuCount;
Hisham Muhammad's avatar
Hisham Muhammad committed
68
69

} ProcessList;
70

Hisham Muhammad's avatar
Hisham Muhammad committed
71
ProcessList* ProcessList_new(UsersTable* ut, Hashtable* pidWhiteList, uid_t userId);
72
void ProcessList_delete(ProcessList* pl);
73
void ProcessList_goThroughEntries(ProcessList* pl);
74

Hisham Muhammad's avatar
Hisham Muhammad committed
75
76
}*/

Hisham Muhammad's avatar
Hisham Muhammad committed
77
ProcessList* ProcessList_init(ProcessList* this, UsersTable* usersTable, Hashtable* pidWhiteList, uid_t userId) {
78
   this->processes = Vector_new(Class(Process), true, DEFAULT_SIZE);
79
   this->processTable = Hashtable_new(140, false);
Hisham Muhammad's avatar
Hisham Muhammad committed
80
   this->usersTable = usersTable;
81
   this->pidWhiteList = pidWhiteList;
Hisham Muhammad's avatar
Hisham Muhammad committed
82
   this->userId = userId;
Hisham Muhammad's avatar
Hisham Muhammad committed
83
   
84
   // tree-view auxiliary buffers
85
   this->processes2 = Vector_new(Class(Process), true, DEFAULT_SIZE);
Hisham Muhammad's avatar
Hisham Muhammad committed
86
   
87
88
   // set later by platform-specific code
   this->cpuCount = 0;
89

90
#ifdef HAVE_LIBHWLOC
91
92
93
94
   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
95
96
   }
   if (topoErr == 0) {
97
98
99
      this->topologyOk = true;
   }
#endif
Hisham Muhammad's avatar
Hisham Muhammad committed
100

101
   this->following = -1;
Hisham Muhammad's avatar
Hisham Muhammad committed
102
103
104
105

   return this;
}

106
void ProcessList_done(ProcessList* this) {
Hisham Muhammad's avatar
Hisham Muhammad committed
107
   Hashtable_delete(this->processTable);
108
109
   Vector_delete(this->processes);
   Vector_delete(this->processes2);
Hisham Muhammad's avatar
Hisham Muhammad committed
110
111
}

112
113
114
115
void ProcessList_setPanel(ProcessList* this, Panel* panel) {
   this->panel = panel;
}

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

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
154
155
Process* ProcessList_get(ProcessList* this, int idx) {
   return (Process*) (Vector_get(this->processes, idx));
Hisham Muhammad's avatar
Hisham Muhammad committed
156
157
158
}

int ProcessList_size(ProcessList* this) {
159
   return (Vector_size(this->processes));
Hisham Muhammad's avatar
Hisham Muhammad committed
160
161
}

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

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

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

234
235
236

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

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

Hisham Muhammad's avatar
Hisham Muhammad committed
259
260
void ProcessList_rebuildPanel(ProcessList* this) {
   const char* incFilter = this->incFilter;
261
262

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

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

290
291
292
293
294
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
Process* ProcessList_getProcess(ProcessList* this, pid_t pid, bool* preExisting, Process_new_fn constructor) {
   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;
   }
}