From 7d9a1d25e53544c922d5e362180b2703a86d32df Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 6 May 2011 20:34:04 +0200 Subject: [PATCH] top: make it possible to feed commands via pipe function old new delta handle_input - 492 +492 mult_lvl_cmp 38 49 +11 packed_usage 28247 28257 +10 top_main 1345 928 -417 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/1 up/down: 513/-417) Total: 96 bytes Signed-off-by: Denys Vlasenko --- procps/top.c | 265 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 155 insertions(+), 110 deletions(-) diff --git a/procps/top.c b/procps/top.c index ee6555188..ed8b56173 100644 --- a/procps/top.c +++ b/procps/top.c @@ -92,9 +92,9 @@ enum { SORT_DEPTH = 3 }; struct globals { top_status_t *top; int ntop; + smallint inverted; #if ENABLE_FEATURE_TOPMEM smallint sort_field; - smallint inverted; #endif #if ENABLE_FEATURE_TOP_SMP_CPU smallint smp_cpu_info; /* one/many cpu info lines? */ @@ -194,9 +194,9 @@ static int mult_lvl_cmp(void* a, void* b) for (i = 0; i < SORT_DEPTH; i++) { cmp_val = (*sort_function[i])(a, b); if (cmp_val != 0) - return cmp_val; + break; } - return 0; + return inverted ? -cmp_val : cmp_val; } static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) @@ -850,8 +850,105 @@ enum { | PSSCAN_PID | PSSCAN_SMAPS | PSSCAN_COMM, + EXIT_MASK = (unsigned)-1, }; +#if ENABLE_FEATURE_USE_TERMIOS +static unsigned handle_input(unsigned scan_mask, unsigned interval) +{ + unsigned char c, *p, buf[64]; + int len; + struct pollfd pfd[1]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; + if (safe_poll(pfd, 1, interval * 1000) <= 0) + return scan_mask; + + len = safe_read(STDIN_FILENO, &buf, sizeof(buf)-1); + if (len <= 0) { /* error/EOF? */ + option_mask32 |= OPT_EOF; + return scan_mask; + } + + buf[len] = 0; + p = buf; + while ((c = *p++) != 0) { + if (c == initial_settings.c_cc[VINTR]) + return EXIT_MASK; + if (c == initial_settings.c_cc[VEOF]) + return EXIT_MASK; + c |= 0x20; /* lowercase */ + if (c == 'q') + return EXIT_MASK; + if (c == 'n') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = pid_sort; + } + if (c == 'm') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = mem_sort; +# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE + sort_function[1] = pcpu_sort; + 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;) + sort_function[0] = pcpu_sort; + sort_function[1] = mem_sort; + sort_function[2] = time_sort; + } + if (c == 't') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = time_sort; + sort_function[1] = mem_sort; + sort_function[2] = pcpu_sort; + } +# if ENABLE_FEATURE_TOPMEM + if (c == 's') { + scan_mask = TOPMEM_MASK; + free(prev_hist); + prev_hist = NULL; + prev_hist_count = 0; + sort_field = (sort_field + 1) % NUM_SORT_FIELD; + } +# endif + if (c == 'r') + inverted ^= 1; +# if ENABLE_FEATURE_TOP_SMP_CPU + /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ + if (c == 'c' || c == '1') { + /* User wants to toggle per cpu <> aggregate */ + if (smp_cpu_info) { + free(cpu_prev_jif); + free(cpu_jif); + cpu_jif = &cur_jif; + cpu_prev_jif = &prev_jif; + } else { + /* Prepare for xrealloc() */ + cpu_jif = cpu_prev_jif = NULL; + } + num_cpus = 0; + smp_cpu_info = !smp_cpu_info; + get_jiffy_counts(); + } +# endif +# endif + } + + return scan_mask; +} +#endif + //usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU //usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ //usage:#else @@ -871,8 +968,9 @@ enum { //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") //usage: IF_FEATURE_TOPMEM( -//usage: "\n"" S: show memory, R: reverse memory sort" +//usage: "\n"" S: show memory" //usage: ) +//usage: "\n"" R: reverse sort" //usage: IF_SHOW_THREADS_OR_TOP_SMP( //usage: "\n"" " //usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") @@ -880,23 +978,34 @@ enum { //usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") //usage: ) //usage: "\n"" Q,^C: exit" +//usage: "\n" +//usage: "\n""Options:" +//usage: "\n"" -b Batch mode" +//usage: "\n"" -n N Exit after N iterations" +//usage: "\n"" -d N Delay between updates" +//usage: IF_FEATURE_TOPMEM( +//usage: "\n"" -m Same as 's' key" +//usage: ) + +/* Interactive testing: + * echo sss | ./busybox top + * - shows memory screen + * echo sss | ./busybox top -bn1 >mem + * - saves memory screen - the *whole* list, not first NROWS porcesses! + * + * TODO: -i STRING param as a better alternative? + */ int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int top_main(int argc UNUSED_PARAM, char **argv) { int iterations; unsigned lines, col; - int lines_rem; unsigned interval; char *str_interval, *str_iterations; unsigned scan_mask = TOP_MASK; #if ENABLE_FEATURE_USE_TERMIOS struct termios new_settings; - struct pollfd pfd[1]; - unsigned char c; - - pfd[0].fd = 0; - pfd[0].events = POLLIN; #endif INIT_G(); @@ -933,15 +1042,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) /* change to /proc */ xchdir("/proc"); -#if ENABLE_FEATURE_USE_TERMIOS - tcgetattr(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(new_settings)); - /* unbuffered input, turn off echo */ - new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); - - bb_signals(BB_FATAL_SIGS, sig_catcher); - tcsetattr_stdin_TCSANOW(&new_settings); -#endif #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE sort_function[0] = pcpu_sort; @@ -951,21 +1051,41 @@ int top_main(int argc UNUSED_PARAM, char **argv) sort_function[0] = mem_sort; #endif - while (1) { +#if ENABLE_FEATURE_USE_TERMIOS + tcgetattr(0, (void *) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(new_settings)); + if (!OPT_BATCH_MODE) { + /* unbuffered input, turn off echo */ + new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + tcsetattr_stdin_TCSANOW(&new_settings); + } + + bb_signals(BB_FATAL_SIGS, sig_catcher); + + /* Eat initial input, if any */ + scan_mask = handle_input(scan_mask, 0); +#endif + + while (scan_mask != EXIT_MASK) { procps_status_t *p = NULL; - lines = 24; /* default */ - col = 79; + if (OPT_BATCH_MODE) { + lines = INT_MAX; + col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ + } else { + lines = 24; /* default */ + col = 79; #if ENABLE_FEATURE_USE_TERMIOS - /* We output to stdout, we need size of stdout (not stdin)! */ - get_terminal_width_height(STDOUT_FILENO, &col, &lines); - if (lines < 5 || col < 10) { - sleep(interval); - continue; - } + /* We output to stdout, we need size of stdout (not stdin)! */ + get_terminal_width_height(STDOUT_FILENO, &col, &lines); + if (lines < 5 || col < 10) { + sleep(interval); + continue; + } #endif - if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ - col = LINE_BUF_SIZE-2; + if (col > LINE_BUF_SIZE - 2) + col = LINE_BUF_SIZE - 2; + } /* read process IDs & status for all the processes */ while ((p = procps_scan(p, scan_mask)) != NULL) { @@ -1033,15 +1153,11 @@ int top_main(int argc UNUSED_PARAM, char **argv) qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); } #endif - lines_rem = lines; - if (OPT_BATCH_MODE) { - lines_rem = INT_MAX; - } if (scan_mask != TOPMEM_MASK) - display_process_list(lines_rem, col); + display_process_list(lines, col); #if ENABLE_FEATURE_TOPMEM else - display_topmem_process_list(lines_rem, col); + display_topmem_process_list(lines, col); #endif clearmems(); if (iterations >= 0 && !--iterations) @@ -1052,81 +1168,10 @@ int top_main(int argc UNUSED_PARAM, char **argv) if (option_mask32 & (OPT_b|OPT_EOF)) /* batch mode, or EOF on stdin ("top 0) { - if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ - option_mask32 |= OPT_EOF; - continue; - } - if (c == initial_settings.c_cc[VINTR]) - break; - c |= 0x20; /* lowercase */ - if (c == 'q') - break; - if (c == 'n') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = pid_sort; - } - if (c == 'm') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = mem_sort; -# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - sort_function[1] = pcpu_sort; - 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;) - sort_function[0] = pcpu_sort; - sort_function[1] = mem_sort; - sort_function[2] = time_sort; - } - if (c == 't') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = time_sort; - sort_function[1] = mem_sort; - sort_function[2] = pcpu_sort; - } -# if ENABLE_FEATURE_TOPMEM - if (c == 's') { - scan_mask = TOPMEM_MASK; - free(prev_hist); - prev_hist = NULL; - prev_hist_count = 0; - sort_field = (sort_field + 1) % NUM_SORT_FIELD; - } - if (c == 'r') - inverted ^= 1; -# endif -# if ENABLE_FEATURE_TOP_SMP_CPU - /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ - if (c == 'c' || c == '1') { - /* User wants to toggle per cpu <> aggregate */ - if (smp_cpu_info) { - free(cpu_prev_jif); - free(cpu_jif); - cpu_jif = &cur_jif; - cpu_prev_jif = &prev_jif; - } else { - /* Prepare for xrealloc() */ - cpu_jif = cpu_prev_jif = NULL; - } - num_cpus = 0; - smp_cpu_info = !smp_cpu_info; - get_jiffy_counts(); - } -# endif -# endif - } + else + scan_mask = handle_input(scan_mask, interval); #endif /* FEATURE_USE_TERMIOS */ - } /* end of "while (1)" */ + } /* end of "while (not Q)" */ bb_putchar('\n'); #if ENABLE_FEATURE_USE_TERMIOS -- 2.25.1