This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git


The following commit(s) were added to refs/heads/master by this push:
     new 62b7e9553 nshlib: top: add Linux-like summary and flicker-free refresh
62b7e9553 is described below

commit 62b7e955300b6dafa4f36d391474d3c8925b8106
Author: Jorge Guzman <[email protected]>
AuthorDate: Fri Jul 10 18:17:54 2026 -0300

    nshlib: top: add Linux-like summary and flicker-free refresh
    
    Print a summary header before the task list in the style of the
    Linux top command: uptime, task counts (total/running/sleeping),
    CPU busy/idle and memory usage, all gathered via sysinfo().
    
    Refresh the screen in place (cursor home + erase-line per row +
    erase-below) instead of clearing the whole screen every cycle,
    which removes the flicker.
    
    Poll stdin during the update interval and exit on 'q', ESC or
    Ctrl-C. Previously the only exit path was the SIGINT handler,
    which requires both CONFIG_ENABLE_ALL_SIGNALS (handler) and
    CONFIG_TTY_SIGINT (serial console converts Ctrl-C into SIGINT,
    default n); on configurations missing either option top could
    not be terminated at all.
    
    Tested on linum-stm32h753bi:nsh.
    
    Signed-off-by: Jorge Guzman <[email protected]>
---
 nshlib/nsh_proccmds.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 120 insertions(+), 4 deletions(-)

diff --git a/nshlib/nsh_proccmds.c b/nshlib/nsh_proccmds.c
index 02a9869aa..8be9fe2d2 100644
--- a/nshlib/nsh_proccmds.c
+++ b/nshlib/nsh_proccmds.c
@@ -26,6 +26,7 @@
 
 #include <nuttx/config.h>
 #include <nuttx/sched.h>
+#include <nuttx/vt100.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -36,6 +37,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <signal.h>
+#include <poll.h>
 #include <sys/ioctl.h>
 #include <sys/sysinfo.h>
 #include <sys/param.h>
@@ -884,6 +886,107 @@ static void top_exit(int signo, FAR siginfo_t *siginfo, 
FAR void *context)
 }
 #endif /* CONFIG_ENABLE_ALL_SIGNALS */
 
+/****************************************************************************
+ * Name: top_state_is_running
+ ****************************************************************************/
+
+static bool top_state_is_running(FAR const char *state)
+{
+  return strncmp(state, "Running", 7) == 0 ||
+         strncmp(state, "Ready", 5) == 0 ||
+         strncmp(state, "Pending", 7) == 0;
+}
+
+/****************************************************************************
+ * Name: top_summary
+ *
+ * Description:
+ *   Print a Linux-top-like summary header: uptime, task counts, CPU
+ *   busy/idle and memory usage.  Lines end with an erase-to-eol so the
+ *   screen can be refreshed in place.
+ *
+ ****************************************************************************/
+
+static void top_summary(FAR struct nsh_vtbl_s *vtbl,
+                        FAR struct nsh_topstatus_s *topstatus)
+{
+  struct sysinfo info;
+  unsigned long uptime;
+  unsigned long busy;
+  size_t running = 0;
+  size_t i;
+
+  for (i = 0; i < topstatus->index; i++)
+    {
+      if (top_state_is_running(topstatus->status[i]->td_state))
+        {
+          running++;
+        }
+    }
+
+  sysinfo(&info);
+  uptime = info.uptime;
+
+  if (uptime >= 86400)
+    {
+      nsh_output(vtbl, VT100_STR_CLEAREOL
+                 "top - up %lud %02lu:%02lu:%02lu\n",
+                 uptime / 86400, (uptime % 86400) / 3600,
+                 (uptime % 3600) / 60, uptime % 60);
+    }
+  else
+    {
+      nsh_output(vtbl, VT100_STR_CLEAREOL "top - up %02lu:%02lu:%02lu\n",
+                 uptime / 3600, (uptime % 3600) / 60, uptime % 60);
+    }
+
+  nsh_output(vtbl, VT100_STR_CLEAREOL
+             "Tasks: %zu total, %zu running, %zu sleeping\n",
+             topstatus->index, running, topstatus->index - running);
+
+  busy = (info.loads[0] * 1000) >> SI_LOAD_SHIFT;
+  nsh_output(vtbl, VT100_STR_CLEAREOL
+             "%%Cpu(s): %2lu.%lu busy, %2lu.%lu idle\n",
+             busy / 10, busy % 10,
+             (1000 - busy) / 10, (1000 - busy) % 10);
+
+  nsh_output(vtbl, VT100_STR_CLEAREOL
+             "Mem : %8lu total, %8lu used, %8lu free\n",
+             info.totalram, info.totalram - info.freeram, info.freeram);
+
+  nsh_output(vtbl, VT100_STR_CLEAREOL "\n");
+}
+
+/****************************************************************************
+ * Name: top_wait_key
+ *
+ * Description:
+ *   Sleep for the update interval, returning true if the user asked to
+ *   quit (q, ESC or Ctrl-C read from stdin).
+ *
+ ****************************************************************************/
+
+static bool top_wait_key(int delay)
+{
+  struct pollfd fds;
+
+  fds.fd = STDIN_FILENO;
+  fds.events = POLLIN;
+
+  if (poll(&fds, 1, delay * 1000) > 0)
+    {
+      char c;
+
+      if (read(STDIN_FILENO, &c, 1) == 1 &&
+          (c == 'q' || c == 0x1b || c == 0x03))
+        {
+          return true;
+        }
+    }
+
+  return false;
+}
+
 #endif
 
 /****************************************************************************
@@ -1417,11 +1520,12 @@ int cmd_top(FAR struct nsh_vtbl_s *vtbl, int argc, FAR 
char **argv)
       tc = nsh_ioctl(vtbl, TIOCSCTTY, getpid());
     }
 
+  nsh_output(vtbl, VT100_STR_CLEARSCREEN);
+
   while (!quit)
     {
       topstatus.index = 0;
-      nsh_output(vtbl, "\033[2J\033[1;1H");
-      ps_title(vtbl, topstatus.heap);
+      nsh_output(vtbl, VT100_STR_CURSORHOME);
 
       if (pidlist)
         {
@@ -1455,17 +1559,29 @@ int cmd_top(FAR struct nsh_vtbl_s *vtbl, int argc, FAR 
char **argv)
       qsort(topstatus.status, topstatus.index,
             sizeof(topstatus.status[0]), top_cmpcpuload);
 
+      top_summary(vtbl, &topstatus);
+
+      nsh_output(vtbl, VT100_STR_CLEAREOL VT100_STR_BOLD);
+      ps_title(vtbl, topstatus.heap);
+      nsh_output(vtbl, VT100_STR_MODESOFF);
+
       for (i = 0; i < MIN(topstatus.index, num); i++)
         {
+          nsh_output(vtbl, VT100_STR_CLEAREOL);
           ps_output(vtbl, topstatus.heap, topstatus.status[i]);
         }
 
       if (vtbl->isctty && tc == 0)
         {
-          nsh_output(vtbl, "use Ctrl+c' to quit\n");
+          nsh_output(vtbl, VT100_STR_CLEAREOL "use 'q' or Ctrl+c to quit\n");
         }
 
-      sleep(delay);
+      nsh_output(vtbl, VT100_STR_CLEAREOS);
+
+      if (top_wait_key(delay))
+        {
+          break;
+        }
     }
 
   if (topstatus.status != NULL)

Reply via email to