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 <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2011-05-06 20:34:04 +02:00
parent a348b4557d
commit 7d9a1d25e5

View File

@ -92,9 +92,9 @@ enum { SORT_DEPTH = 3 };
struct globals { struct globals {
top_status_t *top; top_status_t *top;
int ntop; int ntop;
smallint inverted;
#if ENABLE_FEATURE_TOPMEM #if ENABLE_FEATURE_TOPMEM
smallint sort_field; smallint sort_field;
smallint inverted;
#endif #endif
#if ENABLE_FEATURE_TOP_SMP_CPU #if ENABLE_FEATURE_TOP_SMP_CPU
smallint smp_cpu_info; /* one/many cpu info lines? */ 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++) { for (i = 0; i < SORT_DEPTH; i++) {
cmp_val = (*sort_function[i])(a, b); cmp_val = (*sort_function[i])(a, b);
if (cmp_val != 0) 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) static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif)
@ -850,8 +850,105 @@ enum {
| PSSCAN_PID | PSSCAN_PID
| PSSCAN_SMAPS | PSSCAN_SMAPS
| PSSCAN_COMM, | 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:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU
//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ //usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__
//usage:#else //usage:#else
@ -871,8 +968,9 @@ enum {
//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu")
//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") //usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time")
//usage: IF_FEATURE_TOPMEM( //usage: IF_FEATURE_TOPMEM(
//usage: "\n"" S: show memory, R: reverse memory sort" //usage: "\n"" S: show memory"
//usage: ) //usage: )
//usage: "\n"" R: reverse sort"
//usage: IF_SHOW_THREADS_OR_TOP_SMP( //usage: IF_SHOW_THREADS_OR_TOP_SMP(
//usage: "\n"" " //usage: "\n"" "
//usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") //usage: IF_FEATURE_SHOW_THREADS("H: toggle threads")
@ -880,23 +978,34 @@ enum {
//usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") //usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP")
//usage: ) //usage: )
//usage: "\n"" Q,^C: exit" //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, char **argv) MAIN_EXTERNALLY_VISIBLE;
int top_main(int argc UNUSED_PARAM, char **argv) int top_main(int argc UNUSED_PARAM, char **argv)
{ {
int iterations; int iterations;
unsigned lines, col; unsigned lines, col;
int lines_rem;
unsigned interval; unsigned interval;
char *str_interval, *str_iterations; char *str_interval, *str_iterations;
unsigned scan_mask = TOP_MASK; unsigned scan_mask = TOP_MASK;
#if ENABLE_FEATURE_USE_TERMIOS #if ENABLE_FEATURE_USE_TERMIOS
struct termios new_settings; struct termios new_settings;
struct pollfd pfd[1];
unsigned char c;
pfd[0].fd = 0;
pfd[0].events = POLLIN;
#endif #endif
INIT_G(); INIT_G();
@ -933,15 +1042,6 @@ int top_main(int argc UNUSED_PARAM, char **argv)
/* change to /proc */ /* change to /proc */
xchdir("/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 #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE
sort_function[0] = pcpu_sort; sort_function[0] = pcpu_sort;
@ -951,21 +1051,41 @@ int top_main(int argc UNUSED_PARAM, char **argv)
sort_function[0] = mem_sort; sort_function[0] = mem_sort;
#endif #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; procps_status_t *p = NULL;
lines = 24; /* default */ if (OPT_BATCH_MODE) {
col = 79; lines = INT_MAX;
col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */
} else {
lines = 24; /* default */
col = 79;
#if ENABLE_FEATURE_USE_TERMIOS #if ENABLE_FEATURE_USE_TERMIOS
/* We output to stdout, we need size of stdout (not stdin)! */ /* We output to stdout, we need size of stdout (not stdin)! */
get_terminal_width_height(STDOUT_FILENO, &col, &lines); get_terminal_width_height(STDOUT_FILENO, &col, &lines);
if (lines < 5 || col < 10) { if (lines < 5 || col < 10) {
sleep(interval); sleep(interval);
continue; continue;
} }
#endif #endif
if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ if (col > LINE_BUF_SIZE - 2)
col = LINE_BUF_SIZE-2; col = LINE_BUF_SIZE - 2;
}
/* read process IDs & status for all the processes */ /* read process IDs & status for all the processes */
while ((p = procps_scan(p, scan_mask)) != NULL) { 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); qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort);
} }
#endif #endif
lines_rem = lines;
if (OPT_BATCH_MODE) {
lines_rem = INT_MAX;
}
if (scan_mask != TOPMEM_MASK) if (scan_mask != TOPMEM_MASK)
display_process_list(lines_rem, col); display_process_list(lines, col);
#if ENABLE_FEATURE_TOPMEM #if ENABLE_FEATURE_TOPMEM
else else
display_topmem_process_list(lines_rem, col); display_topmem_process_list(lines, col);
#endif #endif
clearmems(); clearmems();
if (iterations >= 0 && !--iterations) if (iterations >= 0 && !--iterations)
@ -1052,81 +1168,10 @@ int top_main(int argc UNUSED_PARAM, char **argv)
if (option_mask32 & (OPT_b|OPT_EOF)) if (option_mask32 & (OPT_b|OPT_EOF))
/* batch mode, or EOF on stdin ("top </dev/null") */ /* batch mode, or EOF on stdin ("top </dev/null") */
sleep(interval); sleep(interval);
else if (safe_poll(pfd, 1, interval * 1000) > 0) { else
if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ scan_mask = handle_input(scan_mask, interval);
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
}
#endif /* FEATURE_USE_TERMIOS */ #endif /* FEATURE_USE_TERMIOS */
} /* end of "while (1)" */ } /* end of "while (not Q)" */
bb_putchar('\n'); bb_putchar('\n');
#if ENABLE_FEATURE_USE_TERMIOS #if ENABLE_FEATURE_USE_TERMIOS