--- /dev/null
+--- busybox-1.15.3-org/include/libbb.h 2010-04-23 16:11:13.000000000 +0200
++++ busybox-1.15.3/include/libbb.h 2010-04-23 15:07:04.000000000 +0200
+@@ -1279,6 +1279,8 @@
+ DIR *dir;
+ uint8_t shift_pages_to_bytes;
+ uint8_t shift_pages_to_kb;
++ DIR *taskdir;
++ unsigned parentpid;
+ /* Fields are set to 0/NULL if failed to determine (or not requested) */
+ uint16_t argv_len;
+ char *argv0;
+--- busybox-1.15.3-org/libbb/procps.c 2010-04-23 16:11:13.000000000 +0200
++++ busybox-1.15.3/libbb/procps.c 2010-04-23 16:06:55.000000000 +0200
+@@ -178,7 +178,7 @@
+ {
+ struct dirent *entry;
+ char buf[PROCPS_BUFSIZE];
+- char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
++ char filename[sizeof("/proc//task//cmdline//") + sizeof(int)*6];
+ char *filename_tail;
+ long tasknice;
+ unsigned pid;
+@@ -188,11 +188,14 @@
+ if (!sp)
+ sp = alloc_procps_scan();
+
+- for (;;) {
+- entry = readdir(sp->dir);
+- if (entry == NULL) {
+- free_procps_scan(sp);
+- return NULL;
++ for(;;) {
++ if (!sp->taskdir)
++ break;
++ entry = readdir(sp->taskdir);
++ if(entry == NULL) {
++ closedir(sp->taskdir);
++ sp->taskdir = 0;
++ break;
+ }
+ pid = bb_strtou(entry->d_name, NULL, 10);
+ if (errno)
+@@ -216,7 +219,7 @@
+ }
+ #endif
+
+- filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
++ filename_tail = filename + sprintf(filename, "/proc/%u/task/%u/", sp->parentpid, pid);
+
+ if (flags & PSSCAN_UIDGID) {
+ if (stat(filename, &sb))
+@@ -468,6 +471,33 @@
+ break;
+ } /* for (;;) */
+
++ if(sp->taskdir)
++ return sp;
++
++ for (;;) {
++ entry = readdir(sp->dir);
++ if (entry == NULL) {
++ free_procps_scan(sp);
++ return NULL;
++ }
++ pid = bb_strtou(entry->d_name, NULL, 10);
++ if (errno)
++ continue;
++
++ filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
++
++ if (!sp->taskdir) {
++ strcpy(filename_tail, "task");
++ sp->taskdir = opendir(filename);
++ if(!sp->taskdir) {
++ // ignore processes without taskdir
++ continue;
++ }
++ sp->parentpid = pid;
++ return procps_scan(sp, flags);
++ }
++ }
++
+ return sp;
+ }
+
+++ /dev/null
-From b410d4ada73e9ebb30b2b50266a13c30479f5f21 Mon Sep 17 00:00:00 2001
-From: Denys Vlasenko <vda.linux@googlemail.com>
-Date: Sat, 19 Sep 2009 20:29:42 +0000
-Subject: ps,top: add an option to show threads. +260 bytes of code
-
-Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
----
---- busybox-1.15.3-org/include/libbb.h 2010-04-23 11:41:49.000000000 +0200
-+++ busybox-1.15.3/include/libbb.h 2010-04-23 11:07:40.000000000 +0200
-@@ -1277,6 +1277,7 @@
- #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) */
-@@ -1350,6 +1351,7 @@
- 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
---- busybox-1.15.3-org/libbb/procps.c 2010-04-23 11:41:49.000000000 +0200
-+++ busybox-1.15.3/libbb/procps.c 2010-04-23 11:07:40.000000000 +0200
-@@ -110,6 +110,10 @@
- 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 @@
- 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 can:
- * "break": stop parsing, return the data
---- busybox-1.15.3-org/procps/Config.in 2010-04-23 11:41:49.000000000 +0200
-+++ busybox-1.15.3/procps/Config.in 2010-04-23 11:07:40.000000000 +0200
-@@ -188,6 +188,13 @@
- 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 @@
- watch is used to execute a program periodically, showing
- output to the screen.
-
--
- endmenu
---- busybox-1.15.3-org/procps/ps.c 2010-04-23 11:41:49.000000000 +0200
-+++ busybox-1.15.3/procps/ps.c 2010-04-23 11:07:40.000000000 +0200
-@@ -17,7 +17,6 @@
- #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 @@
- #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 @@
- {
- 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 @@
- } 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 @@
- 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 @@
- 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 @@
- | PSSCAN_VSZ
- | PSSCAN_COMM
- | use_selinux
-- ))) {
-+ )) != NULL) {
- #if ENABLE_SELINUX
- if (use_selinux) {
- len = printf("%5u %-32.32s %s ",
---- busybox-1.15.3-org/procps/top.c 2010-04-23 11:42:22.000000000 +0200
-+++ busybox-1.15.3/procps/top.c 2010-04-23 11:13:11.000000000 +0200
-@@ -963,7 +963,10 @@
- /* 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;
-@@ -978,8 +981,9 @@
- #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;
-@@ -994,15 +998,15 @@
- 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();
-@@ -1026,7 +1030,7 @@
- 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
-@@ -1063,6 +1067,11 @@
- 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;)