[PATCH v2 10/13] stackchk: Add rtems_stack_checker_iterate()

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Oct 6 08:23:29 UTC 2022


---
 cpukit/include/rtems/stackchk.h |  75 +++++++++++++++
 cpukit/libmisc/stackchk/check.c | 158 +++++++++++++++++++-------------
 2 files changed, 170 insertions(+), 63 deletions(-)

diff --git a/cpukit/include/rtems/stackchk.h b/cpukit/include/rtems/stackchk.h
index 7968211a51..c836263925 100644
--- a/cpukit/include/rtems/stackchk.h
+++ b/cpukit/include/rtems/stackchk.h
@@ -90,6 +90,81 @@ void rtems_stack_checker_report_usage_with_plugin(
   const rtems_printer *printer
 );
 
+/**
+ * @brief This structure contains the stack information provided by the stack
+ *   checker for a stack.
+ */
+typedef struct {
+  /**
+   * @brief This member contains the object identifier associated with the
+   *   object using the stack.
+   *
+   * For interrupt stacks, the object identifier is the processor index.
+   */
+  rtems_id id;
+
+  /**
+   * @brief This member provides the object name associated with the
+   *   object using the stack.
+   *
+   * For interrupt stacks, the object name is "Interrupt Stack".
+   */
+  const char *name;
+
+  /**
+   * @brief This member provides the begin address of the stack area.
+   */
+  const void *begin;
+
+  /**
+   * @brief This member contains the size in byes of the stack area.
+   */
+  uintptr_t size;
+
+  /**
+   * @brief This member provides the current stack pointer of the stack.
+   *
+   * If the current stack pointer is not available, then the value is set to
+   * NULL.
+   */
+  const void *current;
+
+  /**
+   * @brief This member contains the size in byes of the used stack area.
+   *
+   * If the stack checker is not initialized, then the value is set to
+   * UINTPTR_MAX.
+   */
+  uintptr_t used;
+} rtems_stack_checker_info;
+
+/**
+ * @brief Visitor routines invoked by rtems_stack_checker_iterate() shall have
+ *   this type.
+ *
+ * @param info is the stack information.
+ *
+ * @param arg is the argument passed to rtems_stack_checker_iterate().
+ */
+typedef void ( *rtems_stack_checker_visitor )(
+  const rtems_stack_checker_info *info,
+  void                           *arg
+);
+
+/**
+ * @brief Iterates over all stacks used by the system and invokes the visitor
+ *   routine for each stack.
+ *
+ * This method prints a stack usage report for the curently executing
+ * task.
+ *
+ * @param visitor is the visitor routine invoked for each stack.
+ *
+ * @param arg is the argument passed to each visitor routine invocation during
+ *   the iteration.
+ */
+void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg );
+
 /*************************************************************
  *************************************************************
  **  Prototyped only so the user extension can be installed **
diff --git a/cpukit/libmisc/stackchk/check.c b/cpukit/libmisc/stackchk/check.c
index 48342ce957..53b96f462c 100644
--- a/cpukit/libmisc/stackchk/check.c
+++ b/cpukit/libmisc/stackchk/check.c
@@ -413,134 +413,166 @@ static inline void *Stack_check_Find_high_water_mark(
         return (void *) base;
   #endif
 
-  return (void *)0;
+  return NULL;
 }
 
-static bool Stack_check_Dump_stack_usage(
-  const Stack_Control *stack,
-  const void          *current,
-  const char          *name,
-  uint32_t             id,
-  const rtems_printer *printer
+static void Stack_check_Visit_stack(
+  const Stack_Control        *stack,
+  const void                 *current,
+  const char                 *name,
+  rtems_id                    id,
+  rtems_stack_checker_visitor visit,
+  void                        *arg
 )
 {
-  uint32_t  size;
-  uint32_t  used;
-  void     *low;
-  void     *high_water_mark;
+  rtems_stack_checker_info info;
 
   /* This is likely to occur if the stack checker is not actually enabled */
   if ( stack->area == NULL ) {
-    return false;
+    return;
   }
 
-  low  = Stack_check_Usable_stack_start(stack);
-  size = Stack_check_Usable_stack_size(stack);
+  info.id = id;
+  info.name = name;
+  info.current = current;
+  info.begin  = Stack_check_Usable_stack_start( stack );
+  info.size = Stack_check_Usable_stack_size( stack );
 
-  high_water_mark = Stack_check_Find_high_water_mark(low, size);
+  if ( Stack_check_Initialized ) {
+    void *high_water_mark;
 
-  if ( high_water_mark )
-    used = Stack_check_Calculate_used( low, size, high_water_mark );
-  else
-    used = 0;
+    high_water_mark =
+      Stack_check_Find_high_water_mark( info.begin, info.size );
 
-  rtems_printf(
-    printer,
-    "0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRId32 " ",
-    id,
-    name,
-    (uintptr_t) stack->area,
-    (uintptr_t) stack->area + (uintptr_t) stack->size - 1,
-    (uintptr_t) current,
-    size
-  );
-
-  if (Stack_check_Initialized) {
-    rtems_printf( printer, "%6" PRId32 "\n", used );
+    if ( high_water_mark != NULL ) {
+      info.used =
+        Stack_check_Calculate_used( info.begin, info.size, high_water_mark );
+    } else {
+      info.used = 0;
+    }
   } else {
-    rtems_printf( printer, "N/A\n" );
+    info.used = UINTPTR_MAX;
   }
 
-  return false;
+  ( *visit )( &info, arg );
 }
 
-static bool Stack_check_Dump_threads_usage(
+typedef struct {
+  rtems_stack_checker_visitor visit;
+  void *arg;
+} Stack_check_Visitor;
+
+static bool Stack_check_Visit_thread(
   Thread_Control *the_thread,
   void           *arg
 )
 {
+  Stack_check_Visitor *visitor;
   char                 name[ 22 ];
-  const rtems_printer *printer;
   uintptr_t sp = _CPU_Context_Get_SP( &the_thread->Registers );
 
-  printer = arg;
+  visitor = arg;
   _Thread_Get_name( the_thread, name, sizeof( name ) );
-  Stack_check_Dump_stack_usage(
+  Stack_check_Visit_stack(
     &the_thread->Start.Initial_stack,
     (void *) sp,
     name,
     the_thread->Object.id,
-    printer
+    visitor->visit,
+    visitor->arg
   );
   return false;
 }
 
-static void Stack_check_Dump_interrupt_stack_usage(
-  const Stack_Control *stack,
-  uint32_t             id,
-  const rtems_printer *printer
+static void Stack_check_Visit_interrupt_stack(
+  const Stack_Control        *stack,
+  uint32_t                    id,
+  rtems_stack_checker_visitor visit,
+  void                       *arg
 )
 {
-  Stack_check_Dump_stack_usage(
+  Stack_check_Visit_stack(
     stack,
     NULL,
     "Interrupt Stack",
     id,
-    printer
+    visit,
+    arg
   );
 }
 
-/*
- *  rtems_stack_checker_report_usage
- */
+static void Stack_check_Print_info(
+  const rtems_stack_checker_info *info,
+  void                           *arg
+)
+{
+  const rtems_printer *printer;
+
+  printer = arg;
+
+  rtems_printf(
+    printer,
+    "0x%08" PRIx32 " %-21s 0x%08" PRIxPTR " 0x%08" PRIxPTR " 0x%08" PRIxPTR " %6" PRIuPTR " ",
+    info->id,
+    info->name,
+    (uintptr_t) info->begin,
+    (uintptr_t) info->begin + info->size - 1,
+    (uintptr_t) info->current,
+    info->size
+  );
+
+  if ( info->used != UINTPTR_MAX ) {
+    rtems_printf( printer, "%6" PRIuPTR "\n", info->used );
+  } else {
+    rtems_printf( printer, "N/A\n" );
+  }
+}
 
 void rtems_stack_checker_report_usage_with_plugin(
   const rtems_printer* printer
 )
 {
-  uint32_t cpu_max;
-  uint32_t cpu_index;
-
   rtems_printf(
      printer,
      "                             STACK USAGE BY THREAD\n"
      "ID         NAME                  LOW        HIGH       CURRENT     AVAIL   USED\n"
   );
 
-  /* iterate over all threads and dump the usage */
-  rtems_task_iterate(
-    Stack_check_Dump_threads_usage,
+  rtems_stack_checker_iterate(
+    Stack_check_Print_info,
     RTEMS_DECONST( rtems_printer *, printer )
   );
+}
+
+void rtems_stack_checker_report_usage( void )
+{
+  rtems_printer printer;
+  rtems_print_printer_printk(&printer);
+  rtems_stack_checker_report_usage_with_plugin( &printer );
+}
+
+void rtems_stack_checker_iterate( rtems_stack_checker_visitor visit, void *arg )
+{
+  Stack_check_Visitor visitor;
+  uint32_t            cpu_max;
+  uint32_t            cpu_index;
+
+  visitor.visit = visit;
+  visitor.arg = arg;
+  rtems_task_iterate( Stack_check_Visit_thread, &visitor );
 
   cpu_max = rtems_scheduler_get_processor_maximum();
 
   for ( cpu_index = 0; cpu_index < cpu_max; ++cpu_index ) {
-    Stack_check_Dump_interrupt_stack_usage(
+    Stack_check_Visit_interrupt_stack(
       &Stack_check_Interrupt_stack[ cpu_index ],
       cpu_index,
-      printer
+      visit,
+      arg
     );
   }
 }
 
-void rtems_stack_checker_report_usage( void )
-{
-  rtems_printer printer;
-  rtems_print_printer_printk(&printer);
-  rtems_stack_checker_report_usage_with_plugin( &printer );
-}
-
 static void Stack_check_Prepare_interrupt_stacks( void )
 {
   Stack_Control stack;
-- 
2.35.3



More information about the devel mailing list