aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-09-19 22:29:42 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2009-09-19 22:29:42 +0200
commitb410d4ada73e9ebb30b2b50266a13c30479f5f21 (patch)
tree0d842b9c0885d1cf06fa6aa67a720b31b89cca55
parentf00cfdfae53d8ef623238ecb1001969b5f649cbd (diff)
downloadbusybox-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.h2
-rw-r--r--libbb/procps.c25
-rw-r--r--procps/Config.in8
-rw-r--r--procps/ps.c31
-rw-r--r--procps/top.c21
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
1276typedef struct procps_status_t { 1276typedef 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)
110void FAST_FUNC free_procps_scan(procps_status_t* sp) 110void 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
191config 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
191config UPTIME 198config 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
207endmenu 213endmenu
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;)