ps,top: add an option to show threads. +260 bytes of code
No binary (build failed)
—
(log yok)
| @@ -1275,6 +1275,7 @@ enum { COMM_LEN = 16 }; | |
| #endif | |
| typedef struct procps_status_t { | |
| DIR *dir; | |
| + | IF_FEATURE_SHOW_THREADS(DIR *task_dir;) |
| uint8_t shift_pages_to_bytes; | |
| uint8_t shift_pages_to_kb; | |
| /* Fields are set to 0/NULL if failed to determine (or not requested) */ | |
| @@ -1348,6 +1349,7 @@ enum { | |
| PSSCAN_CPU = (1 << 19) * ENABLE_FEATURE_TOP_SMP_PROCESS, | |
| PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, | |
| PSSCAN_RUIDGID = (1 << 21) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, | |
| + | PSSCAN_TASKS = (1 << 22) * ENABLE_FEATURE_SHOW_THREADS, |
| /* These are all retrieved from proc/NN/stat in one go: */ | |
| PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID | |
| /**/ | PSSCAN_COMM | PSSCAN_STATE | |
| @@ -110,6 +110,10 @@ static procps_status_t* FAST_FUNC alloc_procps_scan(void) | |
| void FAST_FUNC free_procps_scan(procps_status_t* sp) | |
| { | |
| closedir(sp->dir); | |
| + | #if ENABLE_FEATURE_SHOW_THREADS |
| + | if (sp->task_dir) |
| + | closedir(sp->task_dir); |
| + | #endif |
| free(sp->argv0); | |
| free(sp->exe); | |
| IF_SELINUX(free(sp->context);) | |
| @@ -189,14 +193,35 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |
| sp = alloc_procps_scan(); | |
| for (;;) { | |
| + | #if ENABLE_FEATURE_SHOW_THREADS |
| + | if ((flags & PSSCAN_TASKS) && sp->task_dir) { |
| + | entry = readdir(sp->task_dir); |
| + | if (entry) |
| + | goto got_entry; |
| + | closedir(sp->task_dir); |
| + | sp->task_dir = NULL; |
| + | } |
| + | #endif |
| entry = readdir(sp->dir); | |
| if (entry == NULL) { | |
| free_procps_scan(sp); | |
| return NULL; | |
| } | |
| + | IF_FEATURE_SHOW_THREADS(got_entry:) |
| pid = bb_strtou(entry->d_name, NULL, 10); | |
| if (errno) | |
| continue; | |
| + | #if ENABLE_FEATURE_SHOW_THREADS |
| + | if ((flags & PSSCAN_TASKS) && !sp->task_dir) { |
| + | /* We found another /proc/PID. Do not use it, |
| + | * there will be /proc/PID/task/PID (same PID!), |
| + | * so just go ahead and dive into /proc/PID/task. */ |
| + | char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; |
| + | sprintf(task_dir, "/proc/%u/task", pid); |
| + | sp->task_dir = xopendir(task_dir); |
| + | continue; |
| + | } |
| + | #endif |
| /* After this point we have to break, not continue | |
| * ("continue" would mean that current /proc/NNN | |
| @@ -188,6 +188,13 @@ config FEATURE_TOPMEM | |
| help | |
| Enable 's' in top (gives lots of memory info). | |
| + | config FEATURE_SHOW_THREADS |
| + | bool "Support for showing threads in ps/top" |
| + | default n |
| + | depends on PS || TOP |
| + | help |
| + | Enables ps -T option and 'h' command in top |
| + | |
| config UPTIME | |
| bool "uptime" | |
| default n | |
| @@ -203,5 +210,4 @@ config WATCH | |
| watch is used to execute a program periodically, showing | |
| output to the screen. | |
| - | |
| endmenu | |
| @@ -17,7 +17,6 @@ enum { MAX_WIDTH = 2*1024 }; | |
| #if ENABLE_DESKTOP | |
| #include <sys/times.h> /* for times() */ | |
| - | //#include <sys/sysinfo.h> /* for sysinfo() */ |
| #ifndef AT_CLKTCK | |
| #define AT_CLKTCK 17 | |
| #endif | |
| @@ -61,6 +60,7 @@ struct globals { | |
| #define kernel_HZ (G.kernel_HZ ) | |
| #define seconds_since_boot (G.seconds_since_boot) | |
| #define default_o (G.default_o ) | |
| + | #define INIT_G() do { } while (0) |
| #if ENABLE_FEATURE_PS_TIME | |
| /* for ELF executables, notes are pushed before environment and args */ | |
| @@ -452,21 +452,34 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |
| { | |
| procps_status_t *p; | |
| llist_t* opt_o = NULL; | |
| - | IF_SELINUX(int opt;) |
| + | int opt; |
| + | enum { |
| + | OPT_Z = (1 << 0), |
| + | OPT_o = (1 << 1), |
| + | OPT_a = (1 << 2), |
| + | OPT_A = (1 << 3), |
| + | OPT_d = (1 << 4), |
| + | OPT_e = (1 << 5), |
| + | OPT_f = (1 << 6), |
| + | OPT_l = (1 << 7), |
| + | OPT_T = (1 << 8) * ENABLE_FEATURE_SHOW_THREADS, |
| + | }; |
| + | |
| + | INIT_G(); |
| // POSIX: | |
| // -a Write information for all processes associated with terminals | |
| // Implementations may omit session leaders from this list | |
| // -A Write information for all processes | |
| // -d Write information for all processes, except session leaders | |
| - | // -e Write information for all processes (equivalent to -A.) |
| + | // -e Write information for all processes (equivalent to -A) |
| // -f Generate a full listing | |
| // -l Generate a long listing | |
| // -o col1,col2,col3=header | |
| // Select which columns to display | |
| /* We allow (and ignore) most of the above. FIXME */ | |
| opt_complementary = "o::"; | |
| - | IF_SELINUX(opt =) getopt32(argv, "Zo:aAdefl", &opt_o); |
| + | opt = getopt32(argv, "Zo:aAdefl" IF_FEATURE_SHOW_THREADS("T"), &opt_o); |
| if (opt_o) { | |
| do { | |
| parse_o(llist_pop(&opt_o)); | |
| @@ -474,7 +487,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |
| } else { | |
| /* Below: parse_o() needs char*, NOT const char*... */ | |
| #if ENABLE_SELINUX | |
| - | if (!(opt & 1) || !is_selinux_enabled()) { |
| + | if (!(opt & OPT_Z) || !is_selinux_enabled()) { |
| /* no -Z or no SELinux: do not show LABEL */ | |
| strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); | |
| } else | |
| @@ -485,6 +498,10 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |
| parse_o(default_o); | |
| } | |
| post_process(); | |
| + | #if ENABLE_FEATURE_SHOW_THREADS |
| + | if (opt & OPT_T) |
| + | need_flags |= PSSCAN_TASKS; |
| + | #endif |
| /* Was INT_MAX, but some libc's go belly up with printf("%.*s") | |
| * and such large widths */ | |
| @@ -497,7 +514,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv) | |
| format_header(); | |
| p = NULL; | |
| - | while ((p = procps_scan(p, need_flags))) { |
| + | while ((p = procps_scan(p, need_flags)) != NULL) { |
| format_process(p); | |
| } | |
| @@ -558,7 +575,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |
| | PSSCAN_VSZ | |
| | PSSCAN_COMM | |
| | use_selinux | |
| - | ))) { |
| + | )) != NULL) { |
| #if ENABLE_SELINUX | |
| if (use_selinux) { | |
| len = printf("%5u %-32.32s %s ", | |
| @@ -976,7 +976,10 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| /* read process IDs & status for all the processes */ | |
| while ((p = procps_scan(p, scan_mask)) != NULL) { | |
| int n; | |
| - | if (scan_mask == TOP_MASK) { |
| + | #if ENABLE_FEATURE_TOPMEM |
| + | if (scan_mask != TOPMEM_MASK) |
| + | #endif |
| + | { |
| n = ntop; | |
| top = xrealloc_vector(top, 6, ntop++); | |
| top[n].pid = p->pid; | |
| @@ -991,8 +994,9 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| #if ENABLE_FEATURE_TOP_SMP_PROCESS | |
| top[n].last_seen_on_cpu = p->last_seen_on_cpu; | |
| #endif | |
| - | } else { /* TOPMEM */ |
| + | } |
| #if ENABLE_FEATURE_TOPMEM | |
| + | else { /* TOPMEM */ |
| if (!(p->mapped_ro | p->mapped_rw)) | |
| continue; /* kernel threads are ignored */ | |
| n = ntop; | |
| @@ -1007,15 +1011,15 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| topmem[n].dirty = p->private_dirty + p->shared_dirty; | |
| topmem[n].dirty_sh = p->shared_dirty; | |
| topmem[n].stack = p->stack; | |
| - | #endif |
| } | |
| + | #endif |
| } /* end of "while we read /proc" */ | |
| if (ntop == 0) { | |
| bb_error_msg("no process info in /proc"); | |
| break; | |
| } | |
| - | if (scan_mask == TOP_MASK) { |
| + | if (scan_mask != TOPMEM_MASK) { |
| #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | |
| if (!prev_hist_count) { | |
| do_stats(); | |
| @@ -1039,7 +1043,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| if (OPT_BATCH_MODE) { | |
| lines_rem = INT_MAX; | |
| } | |
| - | if (scan_mask == TOP_MASK) |
| + | if (scan_mask != TOPMEM_MASK) |
| display_process_list(lines_rem, col); | |
| #if ENABLE_FEATURE_TOPMEM | |
| else | |
| @@ -1076,6 +1080,13 @@ int top_main(int argc UNUSED_PARAM, char **argv) | |
| sort_function[2] = time_sort; | |
| # endif | |
| } | |
| + | #if ENABLE_FEATURE_SHOW_THREADS |
| + | if (c == 'h' |
| + | IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) |
| + | ) { |
| + | scan_mask ^= PSSCAN_TASKS; |
| + | } |
| + | #endif |
| # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE | |
| if (c == 'p') { | |
| IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) | |