[git commit] top: make it possible to feed commands via pipe

Denys Vlasenko vda.linux at googlemail.com
Fri May 6 18:34:04 UTC 2011


commit: http://git.busybox.net/busybox/commit/?id=7d9a1d25e53544c922d5e362180b2703a86d32df
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 procps/top.c |  265 ++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 155 insertions(+), 110 deletions(-)

diff --git a/procps/top.c b/procps/top.c
index ee65551..ed8b561 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 </dev/null") */
 			sleep(interval);
-		else if (safe_poll(pfd, 1, interval * 1000) > 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
-- 
1.7.3.4



More information about the busybox-cvs mailing list