~ubuntu-branches/ubuntu/dapper/htop/dapper

« back to all changes in this revision

Viewing changes to ProcessList.c

  • Committer: Bazaar Package Importer
  • Author(s): Bartosz Fenski
  • Date: 2004-11-27 10:10:17 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20041127101017-vwknw2ipfvxchno4
Tags: 0.5-1
* New upstream version.
  - fixes problem with wrongly displayed CPU bar (Closes: #283212)

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
 
8
8
#include "ProcessList.h"
9
9
#include "Process.h"
10
 
#include "ProcessFilter.h"
11
10
#include "TypedVector.h"
12
11
#include "UsersTable.h"
13
12
#include "Hashtable.h"
14
13
 
15
 
#include "debug.h"
16
 
 
17
14
#include <sys/types.h>
18
15
#include <sys/stat.h>
19
16
#include <unistd.h>
20
17
#include <dirent.h>
21
18
#include <stdlib.h>
22
19
#include <stdio.h>
23
 
#include <assert.h>
24
20
#include <signal.h>
25
21
#include <stdbool.h>
 
22
#include <sys/utsname.h>
 
23
 
 
24
#include "debug.h"
 
25
#include <assert.h>
26
26
 
27
27
/*{
28
28
#ifndef PROCDIR
39
39
}*/
40
40
 
41
41
/*{
 
42
 
42
43
typedef struct ProcessList_ {
43
44
   TypedVector* processes;
 
45
   TypedVector* processes2;
44
46
   Hashtable* processTable;
45
 
   ProcessFilter* filter;
46
47
   Process* prototype;
47
48
   UsersTable* usersTable;
48
 
   long int totalTime;
49
 
   long int userTime;
50
 
   long int systemTime;
51
 
   long int idleTime;
52
 
   long int niceTime;
53
 
   long int totalPeriod;
54
 
   long int userPeriod;
55
 
   long int systemPeriod;
56
 
   long int idlePeriod;
57
 
   long int nicePeriod;
 
49
 
 
50
   int processorCount;
 
51
   int totalTasks;
 
52
   int runningTasks;
 
53
 
 
54
   long int* totalTime;
 
55
   long int* userTime;
 
56
   long int* systemTime;
 
57
   long int* idleTime;
 
58
   long int* niceTime;
 
59
   long int* totalPeriod;
 
60
   long int* userPeriod;
 
61
   long int* systemPeriod;
 
62
   long int* idlePeriod;
 
63
   long int* nicePeriod;
 
64
 
58
65
   long int totalMem;
59
66
   long int usedMem;
60
67
   long int freeMem;
64
71
   long int totalSwap;
65
72
   long int usedSwap;
66
73
   long int freeSwap;
 
74
 
 
75
   int kernelMajor;
 
76
   int kernelMiddle;
 
77
   int kernelMinor;
 
78
   int kernelTiny;
 
79
 
 
80
   ProcessField* fields;
 
81
   ProcessField sortKey;
 
82
   int direction;
 
83
   bool hideThreads;
 
84
   bool shadowOtherUsers;
 
85
   bool hideKernelThreads;
 
86
   bool treeView;
 
87
   bool highlightBaseName;
 
88
   bool highlightMegabytes;
 
89
 
67
90
} ProcessList;
68
91
}*/
69
92
 
70
 
ProcessList* ProcessList_new(ProcessFilter* filter, UsersTable* usersTable) {
 
93
/* private */
 
94
void ProcessList_getKernelVersion(ProcessList* this) {
 
95
   struct utsname uts;
 
96
   (void) uname(&uts);
 
97
   char** items = String_split(uts.release, '.');
 
98
   this->kernelMajor = atoi(items[0]);
 
99
   this->kernelMiddle = atoi(items[1]);
 
100
   this->kernelMinor = atoi(items[2]);
 
101
   this->kernelTiny = items[3] ? atoi(items[3]) : 0;
 
102
   for (int i = 0; items[i] != NULL; i++) free(items[i]);
 
103
   free(items);
 
104
}
 
105
 
 
106
/* private property */
 
107
ProcessField defaultHeaders[LAST_PROCESSFIELD] = { PID, USER, PRIORITY, NICE, M_SIZE, M_RESIDENT, M_SHARE, STATE, PERCENT_CPU, PERCENT_MEM, TIME, COMM, LAST_PROCESSFIELD };
 
108
 
 
109
ProcessList* ProcessList_new(UsersTable* usersTable) {
71
110
   ProcessList* this;
72
111
   this = malloc(sizeof(ProcessList));
73
 
   this->processes = TypedVector_new(PROCESS_CLASS, true);
 
112
   this->processes = TypedVector_new(PROCESS_CLASS, true, DEFAULT_SIZE);
74
113
   this->processTable = Hashtable_new(20, false);
75
114
   TypedVector_setCompareFunction(this->processes, Process_compare);
76
 
   this->filter = filter;
77
 
   this->prototype = Process_new(this->filter);
78
 
   this->totalTime = 0;
 
115
   this->prototype = Process_new(this);
79
116
   this->usersTable = usersTable;
 
117
   
 
118
   /* tree-view auxiliary buffers */
 
119
   this->processes2 = TypedVector_new(PROCESS_CLASS, true, DEFAULT_SIZE);
 
120
   TypedVector_setCompareFunction(this->processes2, Process_compare);
 
121
 
 
122
   ProcessList_getKernelVersion(this);
 
123
 
 
124
   FILE* status = fopen(PROCSTATFILE, "r");
 
125
   assert(status != NULL);
 
126
   char buffer[256];
 
127
   int procs = -1;
 
128
   do {
 
129
      procs++;
 
130
      fgets(buffer, 255, status);
 
131
   } while (String_startsWith(buffer, "cpu"));
 
132
   fclose(status);
 
133
   this->processorCount = procs - 1;
 
134
   this->totalTime = calloc(procs, sizeof(long int));
 
135
   this->userTime = calloc(procs, sizeof(long int));
 
136
   this->systemTime = calloc(procs, sizeof(long int));
 
137
   this->niceTime = calloc(procs, sizeof(long int));
 
138
   this->idleTime = calloc(procs, sizeof(long int));
 
139
   this->totalPeriod = calloc(procs, sizeof(long int));
 
140
   this->userPeriod = calloc(procs, sizeof(long int));
 
141
   this->systemPeriod = calloc(procs, sizeof(long int));
 
142
   this->nicePeriod = calloc(procs, sizeof(long int));
 
143
   this->idlePeriod = calloc(procs, sizeof(long int));
 
144
   for (int i = 0; i < procs; i++) {
 
145
      this->totalTime[i] = 1;
 
146
      this->totalPeriod[i] = 1;
 
147
   }
 
148
 
 
149
   this->fields = malloc(sizeof(ProcessField) * LAST_PROCESSFIELD);
 
150
   // TODO: turn 'fields' into a TypedVector,
 
151
   // (and ProcessFields into proper objects).
 
152
   for (int i = 0; i < LAST_PROCESSFIELD; i++) {
 
153
      this->fields[i] = defaultHeaders[i];
 
154
   }
 
155
   this->sortKey = PERCENT_CPU;
 
156
   this->direction = 1;
 
157
   this->hideThreads = false;
 
158
   this->shadowOtherUsers = false;
 
159
   this->hideKernelThreads = false;
 
160
   this->treeView = false;
 
161
   this->highlightBaseName = false;
 
162
   this->highlightMegabytes = false;
 
163
 
80
164
   return this;
81
165
}
82
166
 
83
167
void ProcessList_delete(ProcessList* this) {
84
168
   Hashtable_delete(this->processTable);
85
169
   TypedVector_delete(this->processes);
 
170
   TypedVector_delete(this->processes2);
86
171
   Process_delete((Object*)this->prototype);
 
172
 
 
173
   free(this->totalTime);
 
174
   free(this->userTime);
 
175
   free(this->systemTime);
 
176
   free(this->niceTime);
 
177
   free(this->idleTime);
 
178
   free(this->totalPeriod);
 
179
   free(this->userPeriod);
 
180
   free(this->systemPeriod);
 
181
   free(this->nicePeriod);
 
182
   free(this->idlePeriod);
 
183
 
 
184
   free(this->fields);
87
185
   free(this);
88
186
}
89
187
 
 
188
void ProcessList_invertSortOrder(ProcessList* this) {
 
189
   if (this->direction == 1)
 
190
      this->direction = -1;
 
191
   else
 
192
      this->direction = 1;
 
193
}
 
194
 
 
195
void ProcessList_sortKey(ProcessList* this, int delta) {
 
196
   assert(delta == 1 || delta == -1);
 
197
   int i = 0;
 
198
   while (this->fields[i] != this->sortKey)
 
199
      i++;
 
200
   i += delta;
 
201
   if (i < 0) {
 
202
      i = 0;
 
203
      while (this->fields[i] != LAST_PROCESSFIELD)
 
204
         i++;
 
205
      i--;
 
206
   } else if (this->fields[i] == LAST_PROCESSFIELD)
 
207
      i = 0;
 
208
   this->sortKey = this->fields[i];
 
209
   this->direction = 1;
 
210
   // Weird code...
 
211
}
 
212
 
 
213
RichString ProcessList_printHeader(ProcessList* this) {
 
214
   RichString out = RichString_new();
 
215
   ProcessField* fields = this->fields;
 
216
   for (int i = 0; fields[i] != LAST_PROCESSFIELD; i++) {
 
217
      char* field = Process_printField(fields[i]);
 
218
      if (this->sortKey == fields[i])
 
219
         RichString_append(&out, CRT_colors[PANEL_HIGHLIGHT_FOCUS], field);
 
220
      else
 
221
         RichString_append(&out, CRT_colors[PANEL_HEADER_FOCUS], field);
 
222
   }
 
223
   return out;
 
224
}
 
225
 
 
226
 
90
227
void ProcessList_prune(ProcessList* this) {
91
228
   TypedVector_prune(this->processes);
92
229
}
110
247
   return (TypedVector_size(this->processes));
111
248
}
112
249
 
 
250
/* private */
 
251
void ProcessList_buildTree(ProcessList* this, int pid, int level, int indent, int direction) {
 
252
   TypedVector* children = TypedVector_new(PROCESS_CLASS, false, DEFAULT_SIZE);
 
253
 
 
254
   for (int i = 0; i < TypedVector_size(this->processes); i++) {
 
255
      Process* process = (Process*) (TypedVector_get(this->processes, i));
 
256
      if (process->ppid == pid) {
 
257
         Process* process = (Process*) (TypedVector_take(this->processes, i));
 
258
         TypedVector_add(children, process);
 
259
         i--;
 
260
      }
 
261
   }
 
262
   int size = TypedVector_size(children);
 
263
   for (int i = 0; i < size; i++) {
 
264
      Process* process = (Process*) (TypedVector_get(children, i));
 
265
      if (direction == 1)
 
266
         TypedVector_add(this->processes2, process);
 
267
      else
 
268
         TypedVector_insert(this->processes2, 0, process);
 
269
      int nextIndent = indent;
 
270
      if (i < size - 1)
 
271
         nextIndent = indent | (1 << level);
 
272
      ProcessList_buildTree(this, process->pid, level+1, nextIndent, direction);
 
273
      process->indent = indent | (1 << level);
 
274
   }
 
275
   TypedVector_delete(children);
 
276
}
 
277
 
113
278
void ProcessList_sort(ProcessList* this) {
114
 
   TypedVector_sort(this->processes);
 
279
   if (!this->treeView) {
 
280
      TypedVector_sort(this->processes);
 
281
   } else {
 
282
      int direction = this->direction;
 
283
      int sortKey = this->sortKey;
 
284
      this->sortKey = PID;
 
285
      this->direction = 1;
 
286
      TypedVector_sort(this->processes);
 
287
      this->sortKey = sortKey;
 
288
      this->direction = direction;
 
289
      Process* init = (Process*) (TypedVector_take(this->processes, 0));
 
290
      assert(init->pid == 1);
 
291
      init->indent = 0;
 
292
      TypedVector_add(this->processes2, init);
 
293
      ProcessList_buildTree(this, init->pid, 0, 0, direction);
 
294
      TypedVector* t = this->processes;
 
295
      this->processes = this->processes2;
 
296
      this->processes2 = t;
 
297
   }
115
298
}
116
299
 
117
300
/* private */
152
335
      &proc->sigcatch, &proc->wchan, &proc->nswap, &proc->cnswap, 
153
336
      &proc->exit_signal, &proc->processor);
154
337
   
155
 
   // This assert is always valid on 2.4, but _not always valid_ on 2.6.
 
338
   // This assert is always valid on 2.4, but reportedly not always valid on 2.6.
156
339
   // TODO: Check if the semantics of this field has changed.
157
340
   // assert(zero == 0);
158
341
   
168
351
 
169
352
   FILE* status;
170
353
   char buffer[128];
171
 
   status = fopen(PROCMEMINFOFILE, "r");
 
354
  status = fopen(PROCMEMINFOFILE, "r");
172
355
   assert(status != NULL);
173
356
   while (!feof(status)) {
174
357
      fgets(buffer, 128, status);
195
378
 
196
379
   status = fopen(PROCSTATFILE, "r");
197
380
   assert(status != NULL);
198
 
   fscanf(status, "cpu  %ld %ld %ld %ld", &usertime, &nicetime, &systemtime, &idletime);
199
 
   totaltime = usertime + nicetime + systemtime + idletime;
200
 
   long int totalperiod = totaltime - this->totalTime;
 
381
   for (int i = 0; i <= this->processorCount; i++) {
 
382
      int cpuid;
 
383
      if (this->kernelMajor == 2 && this->kernelMiddle <= 4) {
 
384
         if (i == 0) {
 
385
            fscanf(status, "cpu  %ld %ld %ld %ld\n", &usertime, &nicetime, &systemtime, &idletime);
 
386
         } else {
 
387
            fscanf(status, "cpu%d %ld %ld %ld %ld\n", &cpuid, &usertime, &nicetime, &systemtime, &idletime);
 
388
            assert(cpuid == i - 1);
 
389
         }
 
390
         totaltime = usertime + nicetime + systemtime + idletime;
 
391
      } else {
 
392
         long int ioWait, irq, softIrq;
 
393
         if (i == 0)
 
394
            fscanf(status, "cpu  %ld %ld %ld %ld %ld %ld %ld\n", &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq);
 
395
         else {
 
396
            fscanf(status, "cpu%d %ld %ld %ld %ld %ld %ld %ld\n", &cpuid, &usertime, &nicetime, &systemtime, &idletime, &ioWait, &irq, &softIrq);
 
397
            assert(cpuid == i - 1);
 
398
         }
 
399
         systemtime += ioWait + irq + softIrq;
 
400
         totaltime = usertime + nicetime + systemtime + idletime;
 
401
      }
 
402
      assert (usertime >= this->userTime[i]);
 
403
      assert (nicetime >= this->niceTime[i]);
 
404
      assert (systemtime >= this->systemTime[i]);
 
405
      assert (idletime >= this->idleTime[i]);
 
406
      assert (totaltime >= this->totalTime[i]);
 
407
      this->userPeriod[i] = usertime - this->userTime[i];
 
408
      this->nicePeriod[i] = nicetime - this->niceTime[i];
 
409
      this->systemPeriod[i] = systemtime - this->systemTime[i];
 
410
      this->idlePeriod[i] = idletime - this->idleTime[i];
 
411
      this->totalPeriod[i] = totaltime - this->totalTime[i];
 
412
      this->userTime[i] = usertime;
 
413
      this->niceTime[i] = nicetime;
 
414
      this->systemTime[i] = systemtime;
 
415
      this->idleTime[i] = idletime;
 
416
      this->totalTime[i] = totaltime;
 
417
   }
 
418
   float period = (float)this->totalPeriod[0] / this->processorCount;
201
419
   fclose(status);
202
420
 
203
421
   // mark all process as "dirty"
205
423
      Process* p = (Process*) TypedVector_get(this->processes, i);
206
424
      p->updated = false;
207
425
   }
 
426
   
 
427
   this->totalTasks = 0;
 
428
   this->runningTasks = 0;
208
429
 
209
430
   proc = opendir(PROCDIR);
210
431
   assert(proc != NULL);
218
439
      // The RedHat kernel hides threads with a dot.
219
440
      // I believe this is non-standard.
220
441
      bool isThread = false;
221
 
      if (pid == 0 && name[0] == '.') {
 
442
      if ((!this->hideThreads) && pid == 0 && name[0] == '.') {
222
443
         char* tname = name + 1;
223
444
         pid = atoi(tname);
224
445
         if (pid > 0)
244
465
 
245
466
         struct stat sstat;
246
467
         snprintf(statusfilename, MAX_NAME, "%s/%s/stat", PROCDIR, name);
247
 
         stat(statusfilename, &sstat);
 
468
         int statok = stat(statusfilename, &sstat);
 
469
         if (statok == -1)
 
470
            goto errorReadingProcess;
 
471
         
248
472
         char* username = UsersTable_getRef(this->usersTable, sstat.st_uid);
249
473
         if (username) {
250
474
            strncpy(process->user, username, PROCESS_USER_LEN);
264
488
         if(!success) {
265
489
            goto errorReadingProcess;
266
490
         }
267
 
         
 
491
 
268
492
         process->percent_cpu = (process->utime + process->stime - lasttimes) / 
269
 
            (float)totalperiod * 100.0;
 
493
            period * 100.0;
270
494
 
271
495
         if(!existingProcess) {
272
496
            snprintf(statusfilename, MAX_NAME, "%s/%s/cmdline", PROCDIR, name);
306
530
         process->percent_mem = process->m_resident / 
307
531
            (float)(this->usedMem - this->cachedMem - this->buffersMem) * 
308
532
            100.0;
 
533
 
 
534
         this->totalTasks++;
 
535
         if (process->state == 'R') {
 
536
            this->runningTasks++;
 
537
         }
 
538
 
 
539
         if (this->hideKernelThreads && process->m_size == 0)
 
540
            ProcessList_remove(this, process);
 
541
 
309
542
         continue;
310
543
 
311
544
         // Exception handler.
325
558
         p->updated = false;
326
559
   }
327
560
 
328
 
   totalperiod = totaltime - this->totalTime;
329
 
   long int userperiod = usertime - this->userTime;
330
 
   long int niceperiod = nicetime - this->niceTime;
331
 
   long int systemperiod = systemtime - this->systemTime;
332
 
   long int idleperiod = idletime - this->idleTime;
333
 
 
334
 
   this->totalTime = totaltime;
335
 
   this->userTime = usertime;
336
 
   this->niceTime = nicetime;
337
 
   this->systemTime = systemtime;
338
 
   this->idleTime = idletime;
339
 
 
340
 
   this->totalPeriod = totalperiod;
341
 
   this->userPeriod = userperiod;
342
 
   this->nicePeriod = niceperiod;
343
 
   this->systemPeriod = systemperiod;
344
 
   this->idlePeriod = idleperiod;
345
561
}
346
562
 
347
563
void ProcessList_dontCrash(int signal) {