[git commit master] ps, top: add an option to show threads. +260 bytes of code

Denys Vlasenko vda.linux at googlemail.com
Sat Sep 19 20:29:42 UTC 2009


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

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 include/libbb.h  |    2 ++
 libbb/procps.c   |   25 +++++++++++++++++++++++++
 procps/Config.in |    8 +++++++-
 procps/ps.c      |   31 ++++++++++++++++++++++++-------
 procps/top.c     |   21 ++++++++++++++++-----
 5 files changed, 74 insertions(+), 13 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index fd61517..1694d2c 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -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
diff --git a/libbb/procps.c b/libbb/procps.c
index 9746617..845a214 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -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
diff --git a/procps/Config.in b/procps/Config.in
index 9146ff6..6a9a366 100644
--- a/procps/Config.in
+++ b/procps/Config.in
@@ -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
diff --git a/procps/ps.c b/procps/ps.c
index 6523f0f..b35b49c 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -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  ",
diff --git a/procps/top.c b/procps/top.c
index a1ad788..dbaaca1 100644
--- a/procps/top.c
+++ b/procps/top.c
@@ -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;)
-- 
1.6.3.3



More information about the busybox-cvs mailing list