commit aed3754bb3ce0108c94e253ed4a53d85d10b15ab
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Fri Nov 16 13:11:42 2018 +0100

    Introduced some basic stack introspection functionality to threads.
    According information is now given for the shell thread via the 'module:info' command.

diff --git a/core/inc/aos_shell.h b/core/inc/aos_shell.h
index 07d2128..1cf5eee 100644
--- a/core/inc/aos_shell.h
+++ b/core/inc/aos_shell.h
@@ -31,6 +31,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #if (AMIROOS_CFG_SHELL_ENABLE == true)
 #include <hal.h>
 #include <aos_types.h>
+#include <aos_debug.h>
 
 /**
  * @brief   Shell event flag that is emitted when the thread starts.
@@ -358,6 +359,7 @@ extern "C" {
   void aosShellChannelInit(AosShellChannel* channel, BaseAsynchronousChannel* asyncchannel);
   aos_status_t aosShellAddCommand(aos_shell_t* shell, aos_shellcommand_t* cmd);
   aos_status_t aosShellRemoveCommand(aos_shell_t* shell, char* cmd, aos_shellcommand_t** removed);
+  unsigned int aosShellCountCommands(aos_shell_t* shell);
   void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel);
   aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel);
   void aosShellChannelInputEnable(AosShellChannel* channel);
diff --git a/core/inc/aos_thread.h b/core/inc/aos_thread.h
index 7568b49..c08ec00 100644
--- a/core/inc/aos_thread.h
+++ b/core/inc/aos_thread.h
@@ -99,6 +99,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 extern "C" {
 #endif
   void aosThdSleepUntilS(const aos_timestamp_t* t);
+#if (CH_DBG_FILL_THREADS == TRUE)
+  size_t aosThdGetStackPeakUtilization(thread_t* thread);
+#endif
 #ifdef __cplusplus
 }
 #endif
@@ -237,6 +240,29 @@ static inline void aosThdSleepUntil(const aos_timestamp_t* t)
   return;
 }
 
+/**
+ * @brief   Retrieve the stack size of a specific thread in bytes.
+ *
+ * @param[in] thread    Thread to retrieve the stack size from.
+ *
+ * @return  Absolute stack size in bytes.
+ */
+static inline size_t aosThdGetStacksize(thread_t* thread)
+{
+  aosDbgCheck(thread != NULL);
+
+  /*
+   * Working area is structured like:
+   *    thread.wabase (LSB)->[ stack | port specific data | thread structure ]
+   * See the following macros for details:
+   *  - THD_WORKING_AREA
+   *  - THD_WORKING_AREA_SIZE
+   *  - PORT_WA_SIZE
+   */
+  return ((uintptr_t)(thread) - (uintptr_t)(thread->wabase)) -
+         ((size_t)PORT_GUARD_PAGE_SIZE + sizeof(struct port_intctx) + sizeof(struct port_extctx) + (size_t)PORT_INT_REQUIRED_STACK);
+}
+
 #endif /* _AMIROOS_THREAD_H_ */
 
 /** @} */
diff --git a/core/src/aos_shell.c b/core/src/aos_shell.c
index b9559b5..d9ba63f 100644
--- a/core/src/aos_shell.c
+++ b/core/src/aos_shell.c
@@ -1278,6 +1278,27 @@ aos_status_t aosShellRemoveCommand(aos_shell_t *shell, char *cmd, aos_shellcomma
 }
 
 /**
+ * @brief   Count the number of commands assigned to the shell.
+ *
+ * @param[in] shell   The shell to count the commands for.
+ *
+ * @return  The number of commands associated to the shell.
+ */
+unsigned int aosShellCountCommands(aos_shell_t* shell)
+{
+  aosDbgCheck(shell != NULL);
+
+  unsigned int count = 0;
+  aos_shellcommand_t* cmd = shell->commands;
+  while (cmd != NULL) {
+    ++count;
+    cmd = cmd->next;
+  }
+
+  return count;
+}
+
+/**
  * @brief   Add a channel to a AosShellStream.
  *
  * @param[in] stream    The AosShellStream to extend.
@@ -1303,7 +1324,10 @@ void aosShellStreamAddChannel(AosShellStream* stream, AosShellChannel* channel)
  *
  * @param[in] stream    The AosShellStream to modify.
  * @param[in] channel   The channel to remove.
- * @return
+ *
+ * @return              A status value.
+ * @retval AOS_SUCCESS  The channel was removed successfully.
+ * @retval AOS_ERROR    The specified channel was not found to be associated with the shell.
  */
 aos_status_t aosShellStreamRemoveChannel(AosShellStream* stream, AosShellChannel* channel)
 {
diff --git a/core/src/aos_system.c b/core/src/aos_system.c
index 2f8cd38..f692fe4 100644
--- a/core/src/aos_system.c
+++ b/core/src/aos_system.c
@@ -59,10 +59,10 @@ static void _printSystemInfo(BaseSequentialStream* stream);
 static int _shellcmd_configcb(BaseSequentialStream* stream, int argc, char* argv[]);
 static int _shellcmd_infocb(BaseSequentialStream* stream, int argc, char* argv[]);
 static int _shellcmd_shutdowncb(BaseSequentialStream* stream, int argc, char* argv[]);
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
 #if (AMIROOS_CFG_TESTS_ENABLE == true)
 static int _shellcmd_kerneltestcb(BaseSequentialStream* stream, int argc, char* argv[]);
 #endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
 
 /**
  * @brief   Timer to accumulate system uptime.
@@ -498,9 +498,22 @@ static int _shellcmd_infocb(BaseSequentialStream* stream, int argc, char* argv[]
   chprintf(stream, "%10u microseconds\n", (uint16_t)(uptime % MICROSECONDS_PER_MILLISECOND / MICROSECONDS_PER_MICROSECOND));
 #if (AMIROOS_CFG_SSSP_MASTER != true) && (AMIROOS_CFG_PROFILE == true)
   chprintf(stream, "SSSP synchronization offset: %.3fus per %uus\n", _syssyncskew, AMIROOS_CFG_SSSP_SYSSYNCPERIOD);
-#endif
+#endif /* AMIROOS_CFG_SSSP_MASTER != true && AMIROOS_CFG_PROFILE == true */
   _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
 
+#if (AMIROOS_CFG_SHELL_ENABLE == true)
+  // print shell info
+  chprintf(stream, "System shell information:\n");
+  chprintf(stream, "\tnumber of commands:      %u\n", aosShellCountCommands(&aos.shell));
+  chprintf(stream, "\tmaximum line width:      %u characters\n", aos.shell.linesize);
+  chprintf(stream, "\tmaximum #arguments:      %u\n", aos.shell.arglistsize);
+  chprintf(stream, "\tshell thread stack size: %u bytes\n", aosThdGetStacksize(aos.shell.thread));
+#if (CH_DBG_FILL_THREADS == TRUE)
+  chprintf(stream, "\tstack peak utilization:  %u bytes (%.2f%%)\n", aosThdGetStackPeakUtilization(aos.shell.thread), (float)aosThdGetStackPeakUtilization(aos.shell.thread) / (float)aosThdGetStacksize(aos.shell.thread) * 100.0f);
+#endif /* CH_DBG_FILL_THREADS == TRUE */
+  _printSystemInfoSeparator(stream, '=', SYSTEM_INFO_WIDTH);
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
+
   return AOS_OK;
 }
 
@@ -567,7 +580,6 @@ static int _shellcmd_shutdowncb(BaseSequentialStream* stream, int argc, char* ar
     }
   }
 }
-#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
 
 #if (AMIROOS_CFG_TESTS_ENABLE == true) || defined(__DOXYGEN__)
 /**
@@ -591,6 +603,7 @@ static int _shellcmd_kerneltestcb(BaseSequentialStream* stream, int argc, char*
   return retval;
 }
 #endif /* AMIROOS_CFG_TESTS_ENABLE == true */
+#endif /* AMIROOS_CFG_SHELL_ENABLE == true */
 
 /**
  * @brief   Generic callback function for GPIO interrupts.
diff --git a/core/src/aos_thread.c b/core/src/aos_thread.c
index 05c1668..e08fe72 100644
--- a/core/src/aos_thread.c
+++ b/core/src/aos_thread.c
@@ -57,4 +57,30 @@ void aosThdSleepUntilS(const aos_timestamp_t* t)
   return;
 }
 
+#if (CH_DBG_FILL_THREADS == TRUE) || defined(__DOXYGEN__)
+/**
+ * @brief   Calculate the peak stack utilization for a specific thread so far in bytes.
+ *
+ * @param[in] thread    Thread to calculate the stack utilization for.
+ *
+ * @return  Absolute peak stack utilization in bytes.
+ */
+size_t aosThdGetStackPeakUtilization(thread_t* thread)
+{
+  aosDbgCheck(thread != NULL);
+
+  size_t util;
+  uint8_t* ptr = (uint8_t*)thread->wabase;
+
+  chSysLock();
+  while (*ptr == CH_DBG_STACK_FILL_VALUE && ptr < (uint8_t*)thread->wabase + aosThdGetStacksize(thread)) {
+    ++ptr;
+  }
+  util = aosThdGetStacksize(thread) - (ptr - (uint8_t*)thread->wabase);
+  chSysUnlock();
+
+  return util;
+}
+#endif /* CH_DBG_FILL_THREADS == TRUE */
+
 /** @} */
