1 | /* |
---|
2 | * top - a top users display for Unix |
---|
3 | * |
---|
4 | * SYNOPSIS: Linux 1.2.x, 1.3.x 2.0.x, using the /proc filesystem |
---|
5 | * |
---|
6 | * DESCRIPTION: |
---|
7 | * This is the machine-dependent module for Linux 1.2.x, 1.3.x or 2.0.x. |
---|
8 | * |
---|
9 | * LIBS: |
---|
10 | * |
---|
11 | * CFLAGS: -DHAVE_GETOPT -DHAVE_STRERROR -DORDER |
---|
12 | * |
---|
13 | * TERMCAP: -lcurses |
---|
14 | * |
---|
15 | * AUTHOR: Richard Henderson <rth@tamu.edu> |
---|
16 | * Order support added by Alexey Klimkin <kad@klon.tme.mcst.ru> |
---|
17 | */ |
---|
18 | |
---|
19 | #include "top.h" |
---|
20 | #include "machine.h" |
---|
21 | #include "utils.h" |
---|
22 | |
---|
23 | #include <sys/types.h> |
---|
24 | #include <stdio.h> |
---|
25 | #include <fcntl.h> |
---|
26 | #include <unistd.h> |
---|
27 | #include <stdlib.h> |
---|
28 | #include <errno.h> |
---|
29 | #include <dirent.h> |
---|
30 | #include <string.h> |
---|
31 | #include <math.h> |
---|
32 | #include <ctype.h> |
---|
33 | #include <sys/time.h> |
---|
34 | #include <sys/stat.h> |
---|
35 | #include <sys/vfs.h> |
---|
36 | |
---|
37 | #include <sys/param.h> /* for HZ */ |
---|
38 | #include <asm/page.h> /* for PAGE_SHIFT */ |
---|
39 | #include <linux/tasks.h> /* for NR_TASKS */ |
---|
40 | |
---|
41 | #if 0 |
---|
42 | #include <linux/proc_fs.h> /* for PROC_SUPER_MAGIC */ |
---|
43 | #else |
---|
44 | #define PROC_SUPER_MAGIC 0x9fa0 |
---|
45 | #endif |
---|
46 | |
---|
47 | #define PROCFS "/proc" |
---|
48 | extern char *myname; |
---|
49 | extern uid_t proc_owner(pid_t pid); |
---|
50 | |
---|
51 | /*=PROCESS INFORMATION==================================================*/ |
---|
52 | |
---|
53 | struct top_proc |
---|
54 | { |
---|
55 | pid_t pid; |
---|
56 | uid_t uid; |
---|
57 | char name[64]; |
---|
58 | int pri, nice; |
---|
59 | unsigned long size, rss; /* in k */ |
---|
60 | int state; |
---|
61 | unsigned long time; |
---|
62 | double pcpu, wcpu; |
---|
63 | }; |
---|
64 | |
---|
65 | |
---|
66 | /*=STATE IDENT STRINGS==================================================*/ |
---|
67 | |
---|
68 | #define NPROCSTATES 7 |
---|
69 | static char *state_abbrev[NPROCSTATES+1] = |
---|
70 | { |
---|
71 | "", "run", "sleep", "disk", "zomb", "stop", "swap", |
---|
72 | NULL |
---|
73 | }; |
---|
74 | |
---|
75 | static char *procstatenames[NPROCSTATES+1] = |
---|
76 | { |
---|
77 | "", " running, ", " sleeping, ", " uninterruptable, ", |
---|
78 | " zombie, ", " stopped, ", " swapping, ", |
---|
79 | NULL |
---|
80 | }; |
---|
81 | |
---|
82 | #define NCPUSTATES 4 |
---|
83 | static char *cpustatenames[NCPUSTATES+1] = |
---|
84 | { |
---|
85 | "user", "nice", "system", "idle", |
---|
86 | NULL |
---|
87 | }; |
---|
88 | |
---|
89 | #define NMEMSTATS 6 |
---|
90 | static char *memorynames[NMEMSTATS+1] = |
---|
91 | { |
---|
92 | "K used, ", "K free, ", "K shd, ", "K buf Swap: ", |
---|
93 | "K used, ", "K free", |
---|
94 | NULL |
---|
95 | }; |
---|
96 | |
---|
97 | static char fmt_header[] = |
---|
98 | " PID X PRI NICE SIZE RES STATE TIME WCPU CPU COMMAND"; |
---|
99 | |
---|
100 | #ifdef ORDER |
---|
101 | /* these are names given to allowed sorting orders -- first is default */ |
---|
102 | char *ordernames[] = |
---|
103 | {"cpu", "size", "res", "time", NULL}; |
---|
104 | |
---|
105 | /* forward definitions for comparison functions */ |
---|
106 | int compare_cpu(); |
---|
107 | int compare_size(); |
---|
108 | int compare_res(); |
---|
109 | int compare_time(); |
---|
110 | |
---|
111 | int (*proc_compares[])() = { |
---|
112 | compare_cpu, |
---|
113 | compare_size, |
---|
114 | compare_res, |
---|
115 | compare_time, |
---|
116 | NULL }; |
---|
117 | #endif |
---|
118 | |
---|
119 | /*=SYSTEM STATE INFO====================================================*/ |
---|
120 | |
---|
121 | /* these are for calculating cpu state percentages */ |
---|
122 | |
---|
123 | static long cp_time[NCPUSTATES]; |
---|
124 | static long cp_old[NCPUSTATES]; |
---|
125 | static long cp_diff[NCPUSTATES]; |
---|
126 | |
---|
127 | /* for calculating the exponential average */ |
---|
128 | |
---|
129 | static struct timeval lasttime; |
---|
130 | |
---|
131 | /* these are for keeping track of processes */ |
---|
132 | |
---|
133 | #define HASH_SIZE (NR_TASKS * 3 / 2) |
---|
134 | static struct top_proc ptable[HASH_SIZE]; |
---|
135 | static struct top_proc *pactive[NR_TASKS]; |
---|
136 | static struct top_proc **nextactive; |
---|
137 | |
---|
138 | /* these are for passing data back to the machine independant portion */ |
---|
139 | |
---|
140 | static int cpu_states[NCPUSTATES]; |
---|
141 | static int process_states[NPROCSTATES]; |
---|
142 | static int memory_stats[NMEMSTATS]; |
---|
143 | |
---|
144 | /* usefull macros */ |
---|
145 | #define bytetok(x) (((x) + 512) >> 10) |
---|
146 | #define pagetok(x) ((x) << (PAGE_SHIFT - 10)) |
---|
147 | #define HASH(x) (((x) * 1686629713U) % HASH_SIZE) |
---|
148 | |
---|
149 | /*======================================================================*/ |
---|
150 | |
---|
151 | static inline char * |
---|
152 | skip_ws(const char *p) |
---|
153 | { |
---|
154 | while (isspace(*p)) p++; |
---|
155 | return (char *)p; |
---|
156 | } |
---|
157 | |
---|
158 | static inline char * |
---|
159 | skip_token(const char *p) |
---|
160 | { |
---|
161 | while (isspace(*p)) p++; |
---|
162 | while (*p && !isspace(*p)) p++; |
---|
163 | return (char *)p; |
---|
164 | } |
---|
165 | |
---|
166 | |
---|
167 | int |
---|
168 | machine_init(statics) |
---|
169 | struct statics *statics; |
---|
170 | { |
---|
171 | /* make sure the proc filesystem is mounted */ |
---|
172 | { |
---|
173 | struct statfs sb; |
---|
174 | if (statfs(PROCFS, &sb) < 0 || sb.f_type != PROC_SUPER_MAGIC) |
---|
175 | { |
---|
176 | fprintf(stderr, "%s: proc filesystem not mounted on " PROCFS "\n", |
---|
177 | myname); |
---|
178 | return -1; |
---|
179 | } |
---|
180 | } |
---|
181 | |
---|
182 | /* chdir to the proc filesystem to make things easier */ |
---|
183 | chdir(PROCFS); |
---|
184 | |
---|
185 | /* initialize the process hash table */ |
---|
186 | { |
---|
187 | int i; |
---|
188 | for (i = 0; i < HASH_SIZE; ++i) |
---|
189 | ptable[i].pid = -1; |
---|
190 | } |
---|
191 | |
---|
192 | /* fill in the statics information */ |
---|
193 | statics->procstate_names = procstatenames; |
---|
194 | statics->cpustate_names = cpustatenames; |
---|
195 | statics->memory_names = memorynames; |
---|
196 | #ifdef ORDER |
---|
197 | statics->order_names = ordernames; |
---|
198 | #endif |
---|
199 | |
---|
200 | /* all done! */ |
---|
201 | return 0; |
---|
202 | } |
---|
203 | |
---|
204 | |
---|
205 | void |
---|
206 | get_system_info(info) |
---|
207 | struct system_info *info; |
---|
208 | { |
---|
209 | char buffer[4096+1]; |
---|
210 | int fd, len; |
---|
211 | char *p; |
---|
212 | |
---|
213 | /* get load averages */ |
---|
214 | { |
---|
215 | fd = open("loadavg", O_RDONLY); |
---|
216 | len = read(fd, buffer, sizeof(buffer)-1); |
---|
217 | close(fd); |
---|
218 | buffer[len] = '\0'; |
---|
219 | |
---|
220 | info->load_avg[0] = strtod(buffer, &p); |
---|
221 | info->load_avg[1] = strtod(p, &p); |
---|
222 | info->load_avg[2] = strtod(p, &p); |
---|
223 | p = skip_token(p); /* skip running/tasks */ |
---|
224 | p = skip_ws(p); |
---|
225 | if (*p) |
---|
226 | info->last_pid = atoi(p); |
---|
227 | else |
---|
228 | info->last_pid = -1; |
---|
229 | } |
---|
230 | |
---|
231 | /* get the cpu time info */ |
---|
232 | { |
---|
233 | fd = open("stat", O_RDONLY); |
---|
234 | len = read(fd, buffer, sizeof(buffer)-1); |
---|
235 | close(fd); |
---|
236 | buffer[len] = '\0'; |
---|
237 | |
---|
238 | p = skip_token(buffer); /* "cpu" */ |
---|
239 | cp_time[0] = strtoul(p, &p, 0); |
---|
240 | cp_time[1] = strtoul(p, &p, 0); |
---|
241 | cp_time[2] = strtoul(p, &p, 0); |
---|
242 | cp_time[3] = strtoul(p, &p, 0); |
---|
243 | |
---|
244 | /* convert cp_time counts to percentages */ |
---|
245 | percentages(4, cpu_states, cp_time, cp_old, cp_diff); |
---|
246 | } |
---|
247 | |
---|
248 | /* get system wide memory usage */ |
---|
249 | { |
---|
250 | char *p; |
---|
251 | |
---|
252 | fd = open("meminfo", O_RDONLY); |
---|
253 | len = read(fd, buffer, sizeof(buffer)-1); |
---|
254 | close(fd); |
---|
255 | buffer[len] = '\0'; |
---|
256 | |
---|
257 | /* be prepared for extra columns to appear be seeking |
---|
258 | to ends of lines */ |
---|
259 | |
---|
260 | p = strchr(buffer, '\n'); |
---|
261 | p = skip_token(p); /* "Mem:" */ |
---|
262 | p = skip_token(p); /* total memory */ |
---|
263 | memory_stats[0] = strtoul(p, &p, 10); |
---|
264 | memory_stats[1] = strtoul(p, &p, 10); |
---|
265 | memory_stats[2] = strtoul(p, &p, 10); |
---|
266 | memory_stats[3] = strtoul(p, &p, 10); |
---|
267 | |
---|
268 | p = strchr(p, '\n'); |
---|
269 | p = skip_token(p); /* "Swap:" */ |
---|
270 | p = skip_token(p); /* total swap */ |
---|
271 | memory_stats[4] = strtoul(p, &p, 10); |
---|
272 | memory_stats[5] = strtoul(p, &p, 10); |
---|
273 | |
---|
274 | memory_stats[0] = bytetok(memory_stats[0]); |
---|
275 | memory_stats[1] = bytetok(memory_stats[1]); |
---|
276 | memory_stats[2] = bytetok(memory_stats[2]); |
---|
277 | memory_stats[3] = bytetok(memory_stats[3]); |
---|
278 | memory_stats[4] = bytetok(memory_stats[4]); |
---|
279 | memory_stats[5] = bytetok(memory_stats[5]); |
---|
280 | } |
---|
281 | |
---|
282 | /* set arrays and strings */ |
---|
283 | info->cpustates = cpu_states; |
---|
284 | info->memory = memory_stats; |
---|
285 | } |
---|
286 | |
---|
287 | |
---|
288 | static void |
---|
289 | read_one_proc_stat(pid_t pid, struct top_proc *proc) |
---|
290 | { |
---|
291 | char buffer[4096], *p; |
---|
292 | |
---|
293 | /* grab the proc stat info in one go */ |
---|
294 | { |
---|
295 | int fd, len; |
---|
296 | |
---|
297 | sprintf(buffer, "%d/stat", pid); |
---|
298 | |
---|
299 | fd = open(buffer, O_RDONLY); |
---|
300 | len = read(fd, buffer, sizeof(buffer)-1); |
---|
301 | close(fd); |
---|
302 | |
---|
303 | buffer[len] = '\0'; |
---|
304 | } |
---|
305 | |
---|
306 | proc->uid = proc_owner(pid); |
---|
307 | |
---|
308 | /* parse out the status */ |
---|
309 | |
---|
310 | p = buffer; |
---|
311 | p = strchr(p, '(')+1; /* skip pid */ |
---|
312 | { |
---|
313 | char *q = strrchr(p, ')'); |
---|
314 | int len = q-p; |
---|
315 | if (len >= sizeof(proc->name)) |
---|
316 | len = sizeof(proc->name)-1; |
---|
317 | memcpy(proc->name, p, len); |
---|
318 | proc->name[len] = 0; |
---|
319 | p = q+1; |
---|
320 | } |
---|
321 | |
---|
322 | p = skip_ws(p); |
---|
323 | switch (*p++) |
---|
324 | { |
---|
325 | case 'R': proc->state = 1; break; |
---|
326 | case 'S': proc->state = 2; break; |
---|
327 | case 'D': proc->state = 3; break; |
---|
328 | case 'Z': proc->state = 4; break; |
---|
329 | case 'T': proc->state = 5; break; |
---|
330 | case 'W': proc->state = 6; break; |
---|
331 | } |
---|
332 | |
---|
333 | p = skip_token(p); /* skip ppid */ |
---|
334 | p = skip_token(p); /* skip pgrp */ |
---|
335 | p = skip_token(p); /* skip session */ |
---|
336 | p = skip_token(p); /* skip tty */ |
---|
337 | p = skip_token(p); /* skip tty pgrp */ |
---|
338 | p = skip_token(p); /* skip flags */ |
---|
339 | p = skip_token(p); /* skip min flt */ |
---|
340 | p = skip_token(p); /* skip cmin flt */ |
---|
341 | p = skip_token(p); /* skip maj flt */ |
---|
342 | p = skip_token(p); /* skip cmaj flt */ |
---|
343 | |
---|
344 | proc->time = strtoul(p, &p, 10); /* utime */ |
---|
345 | proc->time += strtoul(p, &p, 10); /* stime */ |
---|
346 | |
---|
347 | p = skip_token(p); /* skip cutime */ |
---|
348 | p = skip_token(p); /* skip cstime */ |
---|
349 | |
---|
350 | proc->pri = strtol(p, &p, 10); /* priority */ |
---|
351 | proc->nice = strtol(p, &p, 10); /* nice */ |
---|
352 | |
---|
353 | p = skip_token(p); /* skip timeout */ |
---|
354 | p = skip_token(p); /* skip it_real_val */ |
---|
355 | p = skip_token(p); /* skip start_time */ |
---|
356 | |
---|
357 | proc->size = bytetok(strtoul(p, &p, 10)); /* vsize */ |
---|
358 | proc->rss = pagetok(strtoul(p, &p, 10)); /* rss */ |
---|
359 | |
---|
360 | #if 0 |
---|
361 | /* for the record, here are the rest of the fields */ |
---|
362 | p = skip_token(p); /* skip rlim */ |
---|
363 | p = skip_token(p); /* skip start_code */ |
---|
364 | p = skip_token(p); /* skip end_code */ |
---|
365 | p = skip_token(p); /* skip start_stack */ |
---|
366 | p = skip_token(p); /* skip sp */ |
---|
367 | p = skip_token(p); /* skip pc */ |
---|
368 | p = skip_token(p); /* skip signal */ |
---|
369 | p = skip_token(p); /* skip sigblocked */ |
---|
370 | p = skip_token(p); /* skip sigignore */ |
---|
371 | p = skip_token(p); /* skip sigcatch */ |
---|
372 | p = skip_token(p); /* skip wchan */ |
---|
373 | #endif |
---|
374 | } |
---|
375 | |
---|
376 | |
---|
377 | caddr_t |
---|
378 | get_process_info(struct system_info *si, |
---|
379 | struct process_select *sel, |
---|
380 | int (*compare)()) |
---|
381 | { |
---|
382 | struct timeval thistime; |
---|
383 | double timediff, alpha, beta; |
---|
384 | |
---|
385 | /* calculate the time difference since our last check */ |
---|
386 | gettimeofday(&thistime, 0); |
---|
387 | if (lasttime.tv_sec) |
---|
388 | { |
---|
389 | timediff = ((thistime.tv_sec - lasttime.tv_sec) + |
---|
390 | (thistime.tv_usec - lasttime.tv_usec) * 1e-6); |
---|
391 | } |
---|
392 | else |
---|
393 | timediff = 1e9; |
---|
394 | lasttime = thistime; |
---|
395 | |
---|
396 | /* calculate constants for the exponental average */ |
---|
397 | if (timediff < 30.0) |
---|
398 | { |
---|
399 | alpha = 0.5 * (timediff / 30.0); |
---|
400 | beta = 1.0 - alpha; |
---|
401 | } |
---|
402 | else |
---|
403 | alpha = beta = 0.5; |
---|
404 | timediff *= HZ; /* convert to ticks */ |
---|
405 | |
---|
406 | /* mark all hash table entries as not seen */ |
---|
407 | { |
---|
408 | int i; |
---|
409 | for (i = 0; i < HASH_SIZE; ++i) |
---|
410 | ptable[i].state = 0; |
---|
411 | } |
---|
412 | |
---|
413 | /* read the process information */ |
---|
414 | { |
---|
415 | DIR *dir = opendir("."); |
---|
416 | struct dirent *ent; |
---|
417 | int total_procs = 0; |
---|
418 | struct top_proc **active = pactive; |
---|
419 | |
---|
420 | int show_idle = sel->idle; |
---|
421 | int show_uid = sel->uid != -1; |
---|
422 | |
---|
423 | memset(process_states, 0, sizeof(process_states)); |
---|
424 | |
---|
425 | while ((ent = readdir(dir)) != NULL) |
---|
426 | { |
---|
427 | struct top_proc *proc; |
---|
428 | pid_t pid; |
---|
429 | unsigned long otime; |
---|
430 | |
---|
431 | if (!isdigit(ent->d_name[0])) |
---|
432 | continue; |
---|
433 | |
---|
434 | pid = atoi(ent->d_name); |
---|
435 | |
---|
436 | /* look up hash table entry */ |
---|
437 | proc = &ptable[HASH(pid)]; |
---|
438 | while (proc->pid != pid && proc->pid != -1) |
---|
439 | { |
---|
440 | if (++proc == ptable+HASH_SIZE) |
---|
441 | proc = ptable; |
---|
442 | } |
---|
443 | |
---|
444 | otime = proc->time; |
---|
445 | |
---|
446 | read_one_proc_stat(pid, proc); |
---|
447 | |
---|
448 | if (proc->state == 0) |
---|
449 | continue; |
---|
450 | |
---|
451 | total_procs++; |
---|
452 | process_states[proc->state]++; |
---|
453 | |
---|
454 | if (proc->pid == -1) |
---|
455 | { |
---|
456 | proc->pid = pid; |
---|
457 | proc->wcpu = proc->pcpu = proc->time / timediff; |
---|
458 | } |
---|
459 | else |
---|
460 | { |
---|
461 | proc->pcpu = (proc->time - otime) / timediff; |
---|
462 | proc->wcpu = proc->pcpu * alpha + proc->wcpu * beta; |
---|
463 | } |
---|
464 | |
---|
465 | if ((show_idle || proc->state == 1 || proc->pcpu) && |
---|
466 | (!show_uid || proc->uid == sel->uid)) |
---|
467 | { |
---|
468 | *active++ = proc; |
---|
469 | } |
---|
470 | } |
---|
471 | closedir(dir); |
---|
472 | |
---|
473 | si->p_active = active - pactive; |
---|
474 | si->p_total = total_procs; |
---|
475 | si->procstates = process_states; |
---|
476 | } |
---|
477 | |
---|
478 | /* flush old hash table entries */ |
---|
479 | { |
---|
480 | int i; |
---|
481 | for (i = 0; i < HASH_SIZE; ++i) |
---|
482 | if (ptable[i].state == 0) |
---|
483 | ptable[i].pid = -1; |
---|
484 | } |
---|
485 | |
---|
486 | /* if requested, sort the "active" procs */ |
---|
487 | if (compare && si->p_active) |
---|
488 | qsort(pactive, si->p_active, sizeof(struct top_proc *), compare); |
---|
489 | |
---|
490 | /* don't even pretend that the return value thing here isn't bogus */ |
---|
491 | nextactive = pactive; |
---|
492 | return (caddr_t)0; |
---|
493 | } |
---|
494 | |
---|
495 | |
---|
496 | char * |
---|
497 | format_header(uname_field) |
---|
498 | char *uname_field; |
---|
499 | { |
---|
500 | int uname_len = strlen(uname_field); |
---|
501 | if (uname_len > 8) |
---|
502 | uname_len = 8; |
---|
503 | |
---|
504 | memcpy(strchr(fmt_header, 'X'), uname_field, uname_len); |
---|
505 | |
---|
506 | return fmt_header; |
---|
507 | } |
---|
508 | |
---|
509 | |
---|
510 | char * |
---|
511 | format_next_process(handle, get_userid) |
---|
512 | caddr_t handle; |
---|
513 | char *(*get_userid)(); |
---|
514 | { |
---|
515 | static char fmt[128]; /* static area where result is built */ |
---|
516 | struct top_proc *p = *nextactive++; |
---|
517 | |
---|
518 | sprintf(fmt, |
---|
519 | "%5d %-8.8s %3d %4d %5s %5s %-5s %6s %5.2f%% %5.2f%% %.14s", |
---|
520 | p->pid, |
---|
521 | (*get_userid)(p->uid), |
---|
522 | p->pri, |
---|
523 | p->nice, |
---|
524 | format_k(p->size), |
---|
525 | format_k(p->rss), |
---|
526 | state_abbrev[p->state], |
---|
527 | format_time(p->time / HZ), |
---|
528 | p->wcpu * 100.0, |
---|
529 | p->pcpu * 100.0, |
---|
530 | p->name); |
---|
531 | |
---|
532 | /* return the result */ |
---|
533 | return (fmt); |
---|
534 | } |
---|
535 | |
---|
536 | #ifdef ORDER |
---|
537 | /* comparison routines for qsort */ |
---|
538 | |
---|
539 | /* |
---|
540 | * There are currently four possible comparison routines. main selects |
---|
541 | * one of these by indexing in to the array proc_compares. |
---|
542 | * |
---|
543 | * Possible keys are defined as macros below. Currently these keys are |
---|
544 | * defined: percent cpu, cpu ticks, process state, resident set size, |
---|
545 | * total virtual memory usage. The process states are ordered as follows |
---|
546 | * (from least to most important): WAIT, zombie, sleep, stop, start, run. |
---|
547 | * The array declaration below maps a process state index into a number |
---|
548 | * that reflects this ordering. |
---|
549 | */ |
---|
550 | |
---|
551 | /* First, the possible comparison keys. These are defined in such a way |
---|
552 | that they can be merely listed in the source code to define the actual |
---|
553 | desired ordering. |
---|
554 | */ |
---|
555 | |
---|
556 | #define ORDERKEY_PCTCPU if (dresult = p2->pcpu - p1->pcpu,\ |
---|
557 | (result = dresult > 0.0 ? 1 : dresult < 0.0 ? -1 : 0) == 0) |
---|
558 | #define ORDERKEY_CPTICKS if ((result = p2->time - p1->time) == 0) |
---|
559 | #define ORDERKEY_STATE if ((result = (sort_state[p2->state] - \ |
---|
560 | sort_state[p1->state])) == 0) |
---|
561 | #define ORDERKEY_PRIO if ((result = p2->pri - p1->pri) == 0) |
---|
562 | #define ORDERKEY_RSSIZE if ((result = p2->rss - p1->rss) == 0) |
---|
563 | #define ORDERKEY_MEM if ((result = p2->size - p1->size) == 0) |
---|
564 | |
---|
565 | /* Now the array that maps process state to a weight */ |
---|
566 | |
---|
567 | unsigned char sort_state[] = |
---|
568 | { |
---|
569 | 0, /* empty */ |
---|
570 | 6, /* run */ |
---|
571 | 3, /* sleep */ |
---|
572 | 5, /* disk wait */ |
---|
573 | 1, /* zombie */ |
---|
574 | 2, /* stop */ |
---|
575 | 4 /* swap */ |
---|
576 | }; |
---|
577 | |
---|
578 | |
---|
579 | /* compare_cpu - the comparison function for sorting by cpu percentage */ |
---|
580 | |
---|
581 | int |
---|
582 | compare_cpu ( |
---|
583 | struct top_proc **pp1, |
---|
584 | struct top_proc **pp2) |
---|
585 | { |
---|
586 | register struct top_proc *p1; |
---|
587 | register struct top_proc *p2; |
---|
588 | register long result; |
---|
589 | double dresult; |
---|
590 | |
---|
591 | /* remove one level of indirection */ |
---|
592 | p1 = *pp1; |
---|
593 | p2 = *pp2; |
---|
594 | |
---|
595 | ORDERKEY_PCTCPU |
---|
596 | ORDERKEY_CPTICKS |
---|
597 | ORDERKEY_STATE |
---|
598 | ORDERKEY_PRIO |
---|
599 | ORDERKEY_RSSIZE |
---|
600 | ORDERKEY_MEM |
---|
601 | ; |
---|
602 | |
---|
603 | return result == 0 ? 0 : result < 0 ? -1 : 1; |
---|
604 | } |
---|
605 | |
---|
606 | /* compare_size - the comparison function for sorting by total memory usage */ |
---|
607 | |
---|
608 | int |
---|
609 | compare_size ( |
---|
610 | struct top_proc **pp1, |
---|
611 | struct top_proc **pp2) |
---|
612 | { |
---|
613 | register struct top_proc *p1; |
---|
614 | register struct top_proc *p2; |
---|
615 | register long result; |
---|
616 | double dresult; |
---|
617 | |
---|
618 | /* remove one level of indirection */ |
---|
619 | p1 = *pp1; |
---|
620 | p2 = *pp2; |
---|
621 | |
---|
622 | ORDERKEY_MEM |
---|
623 | ORDERKEY_RSSIZE |
---|
624 | ORDERKEY_PCTCPU |
---|
625 | ORDERKEY_CPTICKS |
---|
626 | ORDERKEY_STATE |
---|
627 | ORDERKEY_PRIO |
---|
628 | ; |
---|
629 | |
---|
630 | return result == 0 ? 0 : result < 0 ? -1 : 1; |
---|
631 | } |
---|
632 | |
---|
633 | /* compare_res - the comparison function for sorting by resident set size */ |
---|
634 | |
---|
635 | int |
---|
636 | compare_res ( |
---|
637 | struct top_proc **pp1, |
---|
638 | struct top_proc **pp2) |
---|
639 | { |
---|
640 | register struct top_proc *p1; |
---|
641 | register struct top_proc *p2; |
---|
642 | register long result; |
---|
643 | double dresult; |
---|
644 | |
---|
645 | /* remove one level of indirection */ |
---|
646 | p1 = *pp1; |
---|
647 | p2 = *pp2; |
---|
648 | |
---|
649 | ORDERKEY_RSSIZE |
---|
650 | ORDERKEY_MEM |
---|
651 | ORDERKEY_PCTCPU |
---|
652 | ORDERKEY_CPTICKS |
---|
653 | ORDERKEY_STATE |
---|
654 | ORDERKEY_PRIO |
---|
655 | ; |
---|
656 | |
---|
657 | return result == 0 ? 0 : result < 0 ? -1 : 1; |
---|
658 | } |
---|
659 | |
---|
660 | /* compare_time - the comparison function for sorting by total cpu time */ |
---|
661 | |
---|
662 | int |
---|
663 | compare_time ( |
---|
664 | struct top_proc **pp1, |
---|
665 | struct top_proc **pp2) |
---|
666 | { |
---|
667 | register struct top_proc *p1; |
---|
668 | register struct top_proc *p2; |
---|
669 | register long result; |
---|
670 | double dresult; |
---|
671 | |
---|
672 | /* remove one level of indirection */ |
---|
673 | p1 = *pp1; |
---|
674 | p2 = *pp2; |
---|
675 | |
---|
676 | ORDERKEY_CPTICKS |
---|
677 | ORDERKEY_PCTCPU |
---|
678 | ORDERKEY_STATE |
---|
679 | ORDERKEY_PRIO |
---|
680 | ORDERKEY_MEM |
---|
681 | ORDERKEY_RSSIZE |
---|
682 | ; |
---|
683 | |
---|
684 | return result == 0 ? 0 : result < 0 ? -1 : 1; |
---|
685 | } |
---|
686 | |
---|
687 | #else /* ORDER */ |
---|
688 | /* |
---|
689 | * proc_compare - comparison function for "qsort" |
---|
690 | * Compares the resource consumption of two processes using five |
---|
691 | * distinct keys. The keys (in descending order of importance) are: |
---|
692 | * percent cpu, cpu ticks, state, resident set size, total virtual |
---|
693 | * memory usage. The process states are ordered as follows (from least |
---|
694 | * to most important): WAIT, zombie, sleep, stop, start, run. The |
---|
695 | * array declaration below maps a process state index into a number |
---|
696 | * that reflects this ordering. |
---|
697 | */ |
---|
698 | |
---|
699 | |
---|
700 | int |
---|
701 | proc_compare (pp1, pp2) |
---|
702 | struct top_proc **pp1, **pp2; |
---|
703 | { |
---|
704 | static unsigned char sort_state[] = |
---|
705 | { |
---|
706 | 0, /* empty */ |
---|
707 | 6, /* run */ |
---|
708 | 3, /* sleep */ |
---|
709 | 5, /* disk wait */ |
---|
710 | 1, /* zombie */ |
---|
711 | 2, /* stop */ |
---|
712 | 4 /* swap */ |
---|
713 | }; |
---|
714 | |
---|
715 | struct top_proc *p1, *p2; |
---|
716 | int result; |
---|
717 | double dresult; |
---|
718 | |
---|
719 | /* remove one level of indirection */ |
---|
720 | p1 = *pp1; |
---|
721 | p2 = *pp2; |
---|
722 | |
---|
723 | /* compare percent cpu (pctcpu) */ |
---|
724 | dresult = p2->pcpu - p1->pcpu; |
---|
725 | if (dresult != 0.0) |
---|
726 | return dresult > 0.0 ? 1 : -1; |
---|
727 | |
---|
728 | /* use cputicks to break the tie */ |
---|
729 | if ((result = p2->time - p1->time) == 0) |
---|
730 | { |
---|
731 | /* use process state to break the tie */ |
---|
732 | if ((result = (sort_state[p2->state] - sort_state[p1->state])) == 0) |
---|
733 | { |
---|
734 | /* use priority to break the tie */ |
---|
735 | if ((result = p2->pri - p1->pri) == 0) |
---|
736 | { |
---|
737 | /* use resident set size (rssize) to break the tie */ |
---|
738 | if ((result = p2->rss - p1->rss) == 0) |
---|
739 | { |
---|
740 | /* use total memory to break the tie */ |
---|
741 | result = (p2->size - p1->size); |
---|
742 | } |
---|
743 | } |
---|
744 | } |
---|
745 | } |
---|
746 | |
---|
747 | return result == 0 ? 0 : result < 0 ? -1 : 1; |
---|
748 | } |
---|
749 | #endif /* ORDER */ |
---|
750 | |
---|
751 | /* |
---|
752 | * proc_owner(pid) - returns the uid that owns process "pid", or -1 if |
---|
753 | * the process does not exist. |
---|
754 | * It is EXTREMLY IMPORTANT that this function work correctly. |
---|
755 | * If top runs setuid root (as in SVR4), then this function |
---|
756 | * is the only thing that stands in the way of a serious |
---|
757 | * security problem. It validates requests for the "kill" |
---|
758 | * and "renice" commands. |
---|
759 | */ |
---|
760 | |
---|
761 | uid_t |
---|
762 | proc_owner(pid) |
---|
763 | pid_t pid; |
---|
764 | { |
---|
765 | struct stat sb; |
---|
766 | char buffer[32]; |
---|
767 | sprintf(buffer, "%d", pid); |
---|
768 | |
---|
769 | if (stat(buffer, &sb) < 0) |
---|
770 | return -1; |
---|
771 | else |
---|
772 | return sb.st_uid; |
---|
773 | } |
---|