diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-19 22:29:42 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-19 22:29:42 +0200 |
commit | b410d4ada73e9ebb30b2b50266a13c30479f5f21 (patch) | |
tree | 0d842b9c0885d1cf06fa6aa67a720b31b89cca55 | |
parent | f00cfdfae53d8ef623238ecb1001969b5f649cbd (diff) | |
download | busybox-w32-b410d4ada73e9ebb30b2b50266a13c30479f5f21.tar.gz busybox-w32-b410d4ada73e9ebb30b2b50266a13c30479f5f21.tar.bz2 busybox-w32-b410d4ada73e9ebb30b2b50266a13c30479f5f21.zip |
ps,top: add an option to show threads. +260 bytes of code
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | include/libbb.h | 2 | ||||
-rw-r--r-- | libbb/procps.c | 25 | ||||
-rw-r--r-- | procps/Config.in | 8 | ||||
-rw-r--r-- | procps/ps.c | 31 | ||||
-rw-r--r-- | procps/top.c | 21 |
5 files changed, 74 insertions, 13 deletions
diff --git a/include/libbb.h b/include/libbb.h index fd61517c2..1694d2c2d 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1275,6 +1275,7 @@ enum { COMM_LEN = 16 }; | |||
1275 | #endif | 1275 | #endif |
1276 | typedef struct procps_status_t { | 1276 | typedef struct procps_status_t { |
1277 | DIR *dir; | 1277 | DIR *dir; |
1278 | IF_FEATURE_SHOW_THREADS(DIR *task_dir;) | ||
1278 | uint8_t shift_pages_to_bytes; | 1279 | uint8_t shift_pages_to_bytes; |
1279 | uint8_t shift_pages_to_kb; | 1280 | uint8_t shift_pages_to_kb; |
1280 | /* Fields are set to 0/NULL if failed to determine (or not requested) */ | 1281 | /* Fields are set to 0/NULL if failed to determine (or not requested) */ |
@@ -1348,6 +1349,7 @@ enum { | |||
1348 | PSSCAN_CPU = (1 << 19) * ENABLE_FEATURE_TOP_SMP_PROCESS, | 1349 | PSSCAN_CPU = (1 << 19) * ENABLE_FEATURE_TOP_SMP_PROCESS, |
1349 | PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, | 1350 | PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, |
1350 | PSSCAN_RUIDGID = (1 << 21) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, | 1351 | PSSCAN_RUIDGID = (1 << 21) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, |
1352 | PSSCAN_TASKS = (1 << 22) * ENABLE_FEATURE_SHOW_THREADS, | ||
1351 | /* These are all retrieved from proc/NN/stat in one go: */ | 1353 | /* These are all retrieved from proc/NN/stat in one go: */ |
1352 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID | 1354 | PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID |
1353 | /**/ | PSSCAN_COMM | PSSCAN_STATE | 1355 | /**/ | PSSCAN_COMM | PSSCAN_STATE |
diff --git a/libbb/procps.c b/libbb/procps.c index 974661785..845a2141b 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -110,6 +110,10 @@ static procps_status_t* FAST_FUNC alloc_procps_scan(void) | |||
110 | void FAST_FUNC free_procps_scan(procps_status_t* sp) | 110 | void FAST_FUNC free_procps_scan(procps_status_t* sp) |
111 | { | 111 | { |
112 | closedir(sp->dir); | 112 | closedir(sp->dir); |
113 | #if ENABLE_FEATURE_SHOW_THREADS | ||
114 | if (sp->task_dir) | ||
115 | closedir(sp->task_dir); | ||
116 | #endif | ||
113 | free(sp->argv0); | 117 | free(sp->argv0); |
114 | free(sp->exe); | 118 | free(sp->exe); |
115 | IF_SELINUX(free(sp->context);) | 119 | IF_SELINUX(free(sp->context);) |
@@ -189,14 +193,35 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
189 | sp = alloc_procps_scan(); | 193 | sp = alloc_procps_scan(); |
190 | 194 | ||
191 | for (;;) { | 195 | for (;;) { |
196 | #if ENABLE_FEATURE_SHOW_THREADS | ||
197 | if ((flags & PSSCAN_TASKS) && sp->task_dir) { | ||
198 | entry = readdir(sp->task_dir); | ||
199 | if (entry) | ||
200 | goto got_entry; | ||
201 | closedir(sp->task_dir); | ||
202 | sp->task_dir = NULL; | ||
203 | } | ||
204 | #endif | ||
192 | entry = readdir(sp->dir); | 205 | entry = readdir(sp->dir); |
193 | if (entry == NULL) { | 206 | if (entry == NULL) { |
194 | free_procps_scan(sp); | 207 | free_procps_scan(sp); |
195 | return NULL; | 208 | return NULL; |
196 | } | 209 | } |
210 | IF_FEATURE_SHOW_THREADS(got_entry:) | ||
197 | pid = bb_strtou(entry->d_name, NULL, 10); | 211 | pid = bb_strtou(entry->d_name, NULL, 10); |
198 | if (errno) | 212 | if (errno) |
199 | continue; | 213 | continue; |
214 | #if ENABLE_FEATURE_SHOW_THREADS | ||
215 | if ((flags & PSSCAN_TASKS) && !sp->task_dir) { | ||
216 | /* We found another /proc/PID. Do not use it, | ||
217 | * there will be /proc/PID/task/PID (same PID!), | ||
218 | * so just go ahead and dive into /proc/PID/task. */ | ||
219 | char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; | ||
220 | sprintf(task_dir, "/proc/%u/task", pid); | ||
221 | sp->task_dir = xopendir(task_dir); | ||
222 | continue; | ||
223 | } | ||
224 | #endif | ||
200 | 225 | ||
201 | /* After this point we have to break, not continue | 226 | /* After this point we have to break, not continue |
202 | * ("continue" would mean that current /proc/NNN | 227 | * ("continue" would mean that current /proc/NNN |
diff --git a/procps/Config.in b/procps/Config.in index 9146ff6bf..6a9a36638 100644 --- a/procps/Config.in +++ b/procps/Config.in | |||
@@ -188,6 +188,13 @@ config FEATURE_TOPMEM | |||
188 | help | 188 | help |
189 | Enable 's' in top (gives lots of memory info). | 189 | Enable 's' in top (gives lots of memory info). |
190 | 190 | ||
191 | config FEATURE_SHOW_THREADS | ||
192 | bool "Support for showing threads in ps/top" | ||
193 | default n | ||
194 | depends on PS || TOP | ||
195 | help | ||
196 | Enables ps -T option and 'h' command in top | ||
197 | |||
191 | config UPTIME | 198 | config UPTIME |
192 | bool "uptime" | 199 | bool "uptime" |
193 | default n | 200 | default n |
@@ -203,5 +210,4 @@ config WATCH | |||
203 | watch is used to execute a program periodically, showing | 210 | watch is used to execute a program periodically, showing |
204 | output to the screen. | 211 | output to the screen. |
205 | 212 | ||
206 | |||
207 | endmenu | 213 | endmenu |
diff --git a/procps/ps.c b/procps/ps.c index 6523f0f38..b35b49c04 100644 --- a/procps/ps.c +++ b/procps/ps.c | |||
@@ -17,7 +17,6 @@ enum { MAX_WIDTH = 2*1024 }; | |||
17 | #if ENABLE_DESKTOP | 17 | #if ENABLE_DESKTOP |
18 | 18 | ||
19 | #include <sys/times.h> /* for times() */ | 19 | #include <sys/times.h> /* for times() */ |
20 | //#include <sys/sysinfo.h> /* for sysinfo() */ | ||
21 | #ifndef AT_CLKTCK | 20 | #ifndef AT_CLKTCK |
22 | #define AT_CLKTCK 17 | 21 | #define AT_CLKTCK 17 |
23 | #endif | 22 | #endif |
@@ -61,6 +60,7 @@ struct globals { | |||
61 | #define kernel_HZ (G.kernel_HZ ) | 60 | #define kernel_HZ (G.kernel_HZ ) |
62 | #define seconds_since_boot (G.seconds_since_boot) | 61 | #define seconds_since_boot (G.seconds_since_boot) |
63 | #define default_o (G.default_o ) | 62 | #define default_o (G.default_o ) |
63 | #define INIT_G() do { } while (0) | ||
64 | 64 | ||
65 | #if ENABLE_FEATURE_PS_TIME | 65 | #if ENABLE_FEATURE_PS_TIME |
66 | /* for ELF executables, notes are pushed before environment and args */ | 66 | /* for ELF executables, notes are pushed before environment and args */ |
@@ -452,21 +452,34 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |||
452 | { | 452 | { |
453 | procps_status_t *p; | 453 | procps_status_t *p; |
454 | llist_t* opt_o = NULL; | 454 | llist_t* opt_o = NULL; |
455 | IF_SELINUX(int opt;) | 455 | int opt; |
456 | enum { | ||
457 | OPT_Z = (1 << 0), | ||
458 | OPT_o = (1 << 1), | ||
459 | OPT_a = (1 << 2), | ||
460 | OPT_A = (1 << 3), | ||
461 | OPT_d = (1 << 4), | ||
462 | OPT_e = (1 << 5), | ||
463 | OPT_f = (1 << 6), | ||
464 | OPT_l = (1 << 7), | ||
465 | OPT_T = (1 << 8) * ENABLE_FEATURE_SHOW_THREADS, | ||
466 | }; | ||
467 | |||
468 | INIT_G(); | ||
456 | 469 | ||
457 | // POSIX: | 470 | // POSIX: |
458 | // -a Write information for all processes associated with terminals | 471 | // -a Write information for all processes associated with terminals |
459 | // Implementations may omit session leaders from this list | 472 | // Implementations may omit session leaders from this list |
460 | // -A Write information for all processes | 473 | // -A Write information for all processes |
461 | // -d Write information for all processes, except session leaders | 474 | // -d Write information for all processes, except session leaders |
462 | // -e Write information for all processes (equivalent to -A.) | 475 | // -e Write information for all processes (equivalent to -A) |
463 | // -f Generate a full listing | 476 | // -f Generate a full listing |
464 | // -l Generate a long listing | 477 | // -l Generate a long listing |
465 | // -o col1,col2,col3=header | 478 | // -o col1,col2,col3=header |
466 | // Select which columns to display | 479 | // Select which columns to display |
467 | /* We allow (and ignore) most of the above. FIXME */ | 480 | /* We allow (and ignore) most of the above. FIXME */ |
468 | opt_complementary = "o::"; | 481 | opt_complementary = "o::"; |
469 | IF_SELINUX(opt =) getopt32(argv, "Zo:aAdefl", &opt_o); | 482 | opt = getopt32(argv, "Zo:aAdefl" IF_FEATURE_SHOW_THREADS("T"), &opt_o); |
470 | if (opt_o) { | 483 | if (opt_o) { |
471 | do { | 484 | do { |
472 | parse_o(llist_pop(&opt_o)); | 485 | parse_o(llist_pop(&opt_o)); |
@@ -474,7 +487,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |||
474 | } else { | 487 | } else { |
475 | /* Below: parse_o() needs char*, NOT const char*... */ | 488 | /* Below: parse_o() needs char*, NOT const char*... */ |
476 | #if ENABLE_SELINUX | 489 | #if ENABLE_SELINUX |
477 | if (!(opt & 1) || !is_selinux_enabled()) { | 490 | if (!(opt & OPT_Z) || !is_selinux_enabled()) { |
478 | /* no -Z or no SELinux: do not show LABEL */ | 491 | /* no -Z or no SELinux: do not show LABEL */ |
479 | strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); | 492 | strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); |
480 | } else | 493 | } else |
@@ -485,6 +498,10 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |||
485 | parse_o(default_o); | 498 | parse_o(default_o); |
486 | } | 499 | } |
487 | post_process(); | 500 | post_process(); |
501 | #if ENABLE_FEATURE_SHOW_THREADS | ||
502 | if (opt & OPT_T) | ||
503 | need_flags |= PSSCAN_TASKS; | ||
504 | #endif | ||
488 | 505 | ||
489 | /* Was INT_MAX, but some libc's go belly up with printf("%.*s") | 506 | /* Was INT_MAX, but some libc's go belly up with printf("%.*s") |
490 | * and such large widths */ | 507 | * and such large widths */ |
@@ -497,7 +514,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |||
497 | format_header(); | 514 | format_header(); |
498 | 515 | ||
499 | p = NULL; | 516 | p = NULL; |
500 | while ((p = procps_scan(p, need_flags))) { | 517 | while ((p = procps_scan(p, need_flags)) != NULL) { |
501 | format_process(p); | 518 | format_process(p); |
502 | } | 519 | } |
503 | 520 | ||
@@ -558,7 +575,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
558 | | PSSCAN_VSZ | 575 | | PSSCAN_VSZ |
559 | | PSSCAN_COMM | 576 | | PSSCAN_COMM |
560 | | use_selinux | 577 | | use_selinux |
561 | ))) { | 578 | )) != NULL) { |
562 | #if ENABLE_SELINUX | 579 | #if ENABLE_SELINUX |
563 | if (use_selinux) { | 580 | if (use_selinux) { |
564 | len = printf("%5u %-32.32s %s ", | 581 | len = printf("%5u %-32.32s %s ", |
diff --git a/procps/top.c b/procps/top.c index a1ad7881e..dbaaca14f 100644 --- a/procps/top.c +++ b/procps/top.c | |||
@@ -976,7 +976,10 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
976 | /* read process IDs & status for all the processes */ | 976 | /* read process IDs & status for all the processes */ |
977 | while ((p = procps_scan(p, scan_mask)) != NULL) { | 977 | while ((p = procps_scan(p, scan_mask)) != NULL) { |
978 | int n; | 978 | int n; |
979 | if (scan_mask == TOP_MASK) { | 979 | #if ENABLE_FEATURE_TOPMEM |
980 | if (scan_mask != TOPMEM_MASK) | ||
981 | #endif | ||
982 | { | ||
980 | n = ntop; | 983 | n = ntop; |
981 | top = xrealloc_vector(top, 6, ntop++); | 984 | top = xrealloc_vector(top, 6, ntop++); |
982 | top[n].pid = p->pid; | 985 | top[n].pid = p->pid; |
@@ -991,8 +994,9 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
991 | #if ENABLE_FEATURE_TOP_SMP_PROCESS | 994 | #if ENABLE_FEATURE_TOP_SMP_PROCESS |
992 | top[n].last_seen_on_cpu = p->last_seen_on_cpu; | 995 | top[n].last_seen_on_cpu = p->last_seen_on_cpu; |
993 | #endif | 996 | #endif |
994 | } else { /* TOPMEM */ | 997 | } |
995 | #if ENABLE_FEATURE_TOPMEM | 998 | #if ENABLE_FEATURE_TOPMEM |
999 | else { /* TOPMEM */ | ||
996 | if (!(p->mapped_ro | p->mapped_rw)) | 1000 | if (!(p->mapped_ro | p->mapped_rw)) |
997 | continue; /* kernel threads are ignored */ | 1001 | continue; /* kernel threads are ignored */ |
998 | n = ntop; | 1002 | n = ntop; |
@@ -1007,15 +1011,15 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1007 | topmem[n].dirty = p->private_dirty + p->shared_dirty; | 1011 | topmem[n].dirty = p->private_dirty + p->shared_dirty; |
1008 | topmem[n].dirty_sh = p->shared_dirty; | 1012 | topmem[n].dirty_sh = p->shared_dirty; |
1009 | topmem[n].stack = p->stack; | 1013 | topmem[n].stack = p->stack; |
1010 | #endif | ||
1011 | } | 1014 | } |
1015 | #endif | ||
1012 | } /* end of "while we read /proc" */ | 1016 | } /* end of "while we read /proc" */ |
1013 | if (ntop == 0) { | 1017 | if (ntop == 0) { |
1014 | bb_error_msg("no process info in /proc"); | 1018 | bb_error_msg("no process info in /proc"); |
1015 | break; | 1019 | break; |
1016 | } | 1020 | } |
1017 | 1021 | ||
1018 | if (scan_mask == TOP_MASK) { | 1022 | if (scan_mask != TOPMEM_MASK) { |
1019 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 1023 | #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
1020 | if (!prev_hist_count) { | 1024 | if (!prev_hist_count) { |
1021 | do_stats(); | 1025 | do_stats(); |
@@ -1039,7 +1043,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1039 | if (OPT_BATCH_MODE) { | 1043 | if (OPT_BATCH_MODE) { |
1040 | lines_rem = INT_MAX; | 1044 | lines_rem = INT_MAX; |
1041 | } | 1045 | } |
1042 | if (scan_mask == TOP_MASK) | 1046 | if (scan_mask != TOPMEM_MASK) |
1043 | display_process_list(lines_rem, col); | 1047 | display_process_list(lines_rem, col); |
1044 | #if ENABLE_FEATURE_TOPMEM | 1048 | #if ENABLE_FEATURE_TOPMEM |
1045 | else | 1049 | else |
@@ -1076,6 +1080,13 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |||
1076 | sort_function[2] = time_sort; | 1080 | sort_function[2] = time_sort; |
1077 | # endif | 1081 | # endif |
1078 | } | 1082 | } |
1083 | #if ENABLE_FEATURE_SHOW_THREADS | ||
1084 | if (c == 'h' | ||
1085 | IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) | ||
1086 | ) { | ||
1087 | scan_mask ^= PSSCAN_TASKS; | ||
1088 | } | ||
1089 | #endif | ||
1079 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | 1090 | # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE |
1080 | if (c == 'p') { | 1091 | if (c == 'p') { |
1081 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | 1092 | IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) |