[PATCH v2 12/13] config: Add CONFIGURE_IDLE_TASK_STORAGE_SIZE

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


By default, allocate the IDLE task storage areas from the RTEMS Workspace.
This avoids having to estimate the thread-local storage size in the default
configuration.

Add the application configuration option CONFIGURE_IDLE_TASK_STORAGE_SIZE to
request a static allocation of the task storage area for IDLE tasks.

Update #3835.
Update #4524.
---
 cpukit/doxygen/appl-config.h                  | 95 +++++++++++++++++--
 cpukit/include/rtems/confdefs/percpu.h        | 14 ---
 cpukit/include/rtems/confdefs/threads.h       |  4 +
 cpukit/include/rtems/confdefs/wkspace.h       | 50 ++++++++--
 cpukit/include/rtems/score/interr.h           |  3 +-
 cpukit/include/rtems/score/stack.h            | 58 ++++++++++-
 cpukit/include/rtems/score/thread.h           |  7 --
 cpukit/sapi/src/interrtext.c                  |  3 +-
 cpukit/score/src/stackallocatorforidle.c      | 43 ++++-----
 .../score/src/stackallocatorforidlewkspace.c  | 60 ++++++++++++
 cpukit/score/src/threadcreateidle.c           | 23 +++--
 spec/build/cpukit/librtemscpu.yml             |  1 +
 spec/build/testsuites/sptests/grp.yml         |  2 +
 spec/build/testsuites/sptests/spfatal36.yml   | 19 ++++
 testsuites/sptests/spfatal36/init.c           | 62 ++++++++++++
 testsuites/sptests/spfatal36/spfatal36.doc    | 11 +++
 testsuites/sptests/spinternalerror02/init.c   |  2 +-
 testsuites/sptests/spstkalloc02/init.c        | 13 +++
 testsuites/sptests/sptls02/init.cc            |  8 +-
 testsuites/validation/ts-default.h            |  5 +-
 testsuites/validation/ts-fatal-sysinit.h      |  2 +
 testsuites/validation/ts-idle.h               |  4 +
 testsuites/validation/ts-validation-acfg-0.c  |  2 +
 testsuites/validation/ts-validation-acfg-1.c  |  2 +
 .../validation/ts-validation-io-kernel.c      |  2 +
 testsuites/validation/ts-validation-tls-1.c   |  3 +
 26 files changed, 418 insertions(+), 80 deletions(-)
 create mode 100644 cpukit/score/src/stackallocatorforidlewkspace.c
 create mode 100644 spec/build/testsuites/sptests/spfatal36.yml
 create mode 100644 testsuites/sptests/spfatal36/init.c
 create mode 100644 testsuites/sptests/spfatal36/spfatal36.doc

diff --git a/cpukit/doxygen/appl-config.h b/cpukit/doxygen/appl-config.h
index d53947c71a..88cd03d328 100644
--- a/cpukit/doxygen/appl-config.h
+++ b/cpukit/doxygen/appl-config.h
@@ -3431,6 +3431,59 @@
  */
 #define CONFIGURE_IDLE_TASK_STACK_SIZE
 
+/* Generated from spec:/acfg/if/idle-task-storage-size */
+
+/**
+ * @brief This configuration option is an integer define.
+ *
+ * If this configuration option is specified, then the task storage areas for
+ * the IDLE tasks are statically allocated by <rtems/confdefs.h>.  The value of
+ * this configuration option defines the size in bytes of the task storage area
+ * of each IDLE task in the system.
+ *
+ * @par Default Value
+ * This configuration option has no default value.  If it is not specified,
+ * then the task storage area for each IDLE task will allocated from the RTEMS
+ * Workspace or through a custom IDLE task stack allocator.
+ *
+ * @par Constraints
+ * The value of the configuration option shall be greater than or equal to
+ * #CONFIGURE_IDLE_TASK_STACK_SIZE.
+ *
+ * @par Notes
+ * @parblock
+ * By default, the IDLE task storage areas are allocated from the RTEMS
+ * Workspace.  Applications which do not want to use a heap allocator can use
+ * this configuration option to use statically allocated memory for the IDLE
+ * task storage areas.  The task storage area contains the task stack, the
+ * thread-local storage, and the floating-point context on architectures with a
+ * separate floating-point context.  The size of the thread-local storage area
+ * is defined at link time or by the
+ * #CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE configuration option.  You have
+ * to estimate the actual thread-local storage size if you want to use this
+ * configuration option.  If the IDLE task stack size would be less than the
+ * value defined by the #CONFIGURE_IDLE_TASK_STACK_SIZE configuration option,
+ * for example because the thread-local storage size is larger than expected,
+ * then the system terminates with the INTERNAL_ERROR_CORE fatal source and the
+ * INTERNAL_ERROR_IDLE_THREAD_STACK_TOO_SMALL fatal code during system
+ * initialization.
+ *
+ * The value of this configuration option is passed to
+ * RTEMS_TASK_STORAGE_SIZE() by <rtems/confdefs.h> to determine the actual size
+ * of the statically allocated area to take architecture-specific overheads
+ * into account.
+ *
+ * The
+ *
+ * * ``CONFIGURE_IDLE_TASK_STORAGE_SIZE``, and
+ *
+ * * #CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+ *
+ * configuration options are mutually exclusive.
+ * @endparblock
+ */
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE
+
 /** @} */
 
 /* Generated from spec:/acfg/if/group-mpci */
@@ -4826,23 +4879,45 @@
  * @brief This configuration option is an initializer define.
  *
  * The value of this configuration option is the address for the stack
- * allocator allocate handler used to allocate the task stack of each IDLE
- * task.
+ * allocator allocate handler used to allocate the task storage area of each
+ * IDLE task.
  *
  * @par Default Value
- * The default value is ``_Stack_Allocator_allocate_for_idle_default``, which
- * indicates that IDLE task stacks will be allocated from an area statically
- * allocated by ``<rtems/confdefs.h>``.
+ * By default, the IDLE task storage area will be allocated from the RTEMS
+ * Workspace.
  *
  * @par Value Constraints
- * The value of this configuration option shall be defined to a valid function
- * pointer of the type ``void *( *allocate )( uint32_t, size_t * )``.
+ * @parblock
+ * The following constraints apply to this configuration option:
+ *
+ * * The value of the configuration option shall be defined to a valid function
+ *   pointer of the type ``void *( *allocate )( uint32_t, size_t * )``.
+ *
+ * * The IDLE task stack allocator shall return a pointer to the allocated
+ *   memory area or terminate the system with a fatal error if the allocation
+ *   request cannot be satisfied.
+ *
+ * * The IDLE task stack allocator may increase the size of the allocated
+ *   memory area.
+ * @endparblock
  *
  * @par Notes
+ * @parblock
  * This configuration option is independent of the other thread stack allocator
- * configuration options.  It is assumed that any memory allocated for the
- * stack of an IDLE task will not be from the RTEMS Workspace or the memory
- * statically allocated by default.
+ * configuration options.  It is assumed that any memory allocated for the task
+ * storage area of an IDLE task will not be from the RTEMS Workspace.
+ *
+ * The IDLE task stack allocator may increase the size of the allocated memory
+ * area to account for the actually allocated memory area.
+ *
+ * The
+ *
+ * * #CONFIGURE_IDLE_TASK_STORAGE_SIZE, and
+ *
+ * * ``CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE``
+ *
+ * configuration options are mutually exclusive.
+ * @endparblock
  */
 #define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
 
diff --git a/cpukit/include/rtems/confdefs/percpu.h b/cpukit/include/rtems/confdefs/percpu.h
index b91590bfd9..a6b35e0eaf 100644
--- a/cpukit/include/rtems/confdefs/percpu.h
+++ b/cpukit/include/rtems/confdefs/percpu.h
@@ -136,20 +136,6 @@ RTEMS_DEFINE_GLOBAL_SYMBOL(
 
 const size_t _Thread_Idle_stack_size = CONFIGURE_IDLE_TASK_STACK_SIZE;
 
-/*
- * If the user provides a custom idle stack allocator, then we do not need
- * memory reserved for the stacks but the symbol is still referenced in
- * threadcreateidle.c. The code path just never uses it. Make it minimal
- * size to proceed.
- */
-#ifndef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
-  char _Thread_Idle_stacks[
-    _CONFIGURE_MAXIMUM_PROCESSORS
-      * ( CONFIGURE_IDLE_TASK_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
-  ] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
-  RTEMS_SECTION( ".rtemsstack.idle" );
-#endif
-
 #if defined(CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION) && \
   !defined(CONFIGURE_IDLE_TASK_BODY)
   #error "If you define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION, then you must define CONFIGURE_IDLE_TASK_BODY as well"
diff --git a/cpukit/include/rtems/confdefs/threads.h b/cpukit/include/rtems/confdefs/threads.h
index 4040bcb50a..5ccfffaf6e 100644
--- a/cpukit/include/rtems/confdefs/threads.h
+++ b/cpukit/include/rtems/confdefs/threads.h
@@ -235,6 +235,10 @@ const size_t _Thread_Control_add_on_count =
 #endif
 
 const size_t _Thread_Initial_thread_count =
+#if !defined(CONFIGURE_IDLE_TASK_STORAGE_SIZE) && \
+  !defined(CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE)
+  _CONFIGURE_MAXIMUM_PROCESSORS +
+#endif
   rtems_resource_maximum_per_allocation( _CONFIGURE_TASKS ) +
   rtems_resource_maximum_per_allocation( CONFIGURE_MAXIMUM_POSIX_THREADS );
 
diff --git a/cpukit/include/rtems/confdefs/wkspace.h b/cpukit/include/rtems/confdefs/wkspace.h
index 82de8633bf..5b80872d2b 100644
--- a/cpukit/include/rtems/confdefs/wkspace.h
+++ b/cpukit/include/rtems/confdefs/wkspace.h
@@ -47,6 +47,7 @@
 #include <rtems/confdefs/inittask.h>
 #include <rtems/confdefs/initthread.h>
 #include <rtems/confdefs/objectsposix.h>
+#include <rtems/confdefs/percpu.h>
 #include <rtems/confdefs/threads.h>
 #include <rtems/confdefs/wkspacesupport.h>
 #include <rtems/score/coremsg.h>
@@ -111,8 +112,18 @@
     + 1024 * CONFIGURE_MEMORY_OVERHEAD \
     + _CONFIGURE_HEAP_HANDLER_OVERHEAD )
 
+#if defined(CONFIGURE_IDLE_TASK_STORAGE_SIZE) || \
+  defined(CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE)
+  #define _CONFIGURE_IDLE_TASK_STACKS 0
+#else
+  #define _CONFIGURE_IDLE_TASK_STACKS \
+    ( _CONFIGURE_MAXIMUM_PROCESSORS * \
+      _Configure_From_stackspace( CONFIGURE_IDLE_TASK_STACK_SIZE ) )
+#endif
+
 #define _CONFIGURE_STACK_SPACE_SIZE \
   ( _CONFIGURE_INIT_TASK_STACK_EXTRA \
+    + _CONFIGURE_IDLE_TASK_STACKS \
     + _CONFIGURE_POSIX_INIT_THREAD_STACK_EXTRA \
     + _CONFIGURE_LIBBLOCK_TASKS_STACK_EXTRA \
     + CONFIGURE_EXTRA_TASK_STACKS \
@@ -212,15 +223,40 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
   #error "CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR must be both defined or both undefined"
 #endif
 
-/*
- * Custom IDLE thread stacks allocator. If this is provided, it is assumed
- * that the allocator is providing its own memory for these stacks.
- */
-#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
-  const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
-    CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
+#ifdef CONFIGURE_IDLE_TASK_STORAGE_SIZE
+  #ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+    #error "CONFIGURE_IDLE_TASK_STORAGE_SIZE and CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE are mutually exclusive"
+  #endif
+
+  #define _CONFIGURE_IDLE_TASK_STORAGE_SIZE \
+    RTEMS_ALIGN_UP( \
+      RTEMS_TASK_STORAGE_SIZE( \
+        CONFIGURE_IDLE_TASK_STORAGE_SIZE, \
+        RTEMS_DEFAULT_ATTRIBUTES \
+      ), \
+      CPU_INTERRUPT_STACK_ALIGNMENT \
+    )
+
+  const size_t _Stack_Allocator_allocate_for_idle_storage_size =
+    _CONFIGURE_IDLE_TASK_STORAGE_SIZE;
+
+  char _Stack_Allocator_allocate_for_idle_storage_areas[
+    _CONFIGURE_MAXIMUM_PROCESSORS * _CONFIGURE_IDLE_TASK_STORAGE_SIZE
+  ] RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
+  RTEMS_SECTION( ".rtemsstack.idle" );
+
+  #define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE \
+    _Stack_Allocator_allocate_for_idle_static
 #endif
 
+#ifndef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+  #define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE \
+    _Stack_Allocator_allocate_for_idle_workspace;
+#endif
+
+const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+  CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
+
 #ifdef CONFIGURE_DIRTY_MEMORY
   RTEMS_SYSINIT_ITEM(
     _Memory_Dirty_free_areas,
diff --git a/cpukit/include/rtems/score/interr.h b/cpukit/include/rtems/score/interr.h
index d0ecf0f5c8..f21e8d58a1 100644
--- a/cpukit/include/rtems/score/interr.h
+++ b/cpukit/include/rtems/score/interr.h
@@ -229,7 +229,8 @@ typedef enum {
   INTERNAL_ERROR_NO_MEMORY_FOR_PER_CPU_DATA = 40,
   INTERNAL_ERROR_TOO_LARGE_TLS_SIZE = 41,
   INTERNAL_ERROR_RTEMS_INIT_TASK_CONSTRUCT_FAILED = 42,
-  INTERNAL_ERROR_IDLE_THREAD_CREATE_FAILED = 43
+  INTERNAL_ERROR_IDLE_THREAD_CREATE_FAILED = 43,
+  INTERNAL_ERROR_NO_MEMORY_FOR_IDLE_TASK_STORAGE = 44
 } Internal_errors_Core_list;
 
 typedef CPU_Uint32ptr Internal_errors_t;
diff --git a/cpukit/include/rtems/score/stack.h b/cpukit/include/rtems/score/stack.h
index 7577ca0474..9326480373 100644
--- a/cpukit/include/rtems/score/stack.h
+++ b/cpukit/include/rtems/score/stack.h
@@ -11,8 +11,8 @@
  */
 
 /*
- *  COPYRIGHT (c) 1989-2006.
- *  On-Line Applications Research Corporation (OAR).
+ * Copyright (C) 2022 embedded brains GmbH
+ * Copyright (C) 1989, 2021 On-Line Applications Research Corporation (OAR)
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -172,7 +172,57 @@ extern const Stack_Allocator_free _Stack_Allocator_free;
  */
 void _Stack_Allocator_do_initialize( void );
 
-/** @} */
+/**
+ * @brief Allocates the IDLE thread storage area from the workspace.
+ *
+ * If the thread storage area cannot be allocated, then the
+ * ::INTERNAL_ERROR_NO_MEMORY_FOR_IDLE_TASK_STACK fatal error will occur.
+ *
+ * @param unused is an unused parameter.
+ *
+ * @param stack_size[in] is pointer to a size_t object.  On function entry, the
+ *   object contains the size of the task storage area to allocate in bytes.
+ *
+ * @return Returns a pointer to the begin of the allocated task storage area.
+ */
+void *_Stack_Allocator_allocate_for_idle_workspace(
+  uint32_t  unused,
+  size_t   *storage_size
+);
+
+/**
+ * @brief The size in bytes of the idle thread storage area used by
+ *   _Stack_Allocator_allocate_for_idle_static().
+ *
+ * Application provided via <rtems/confdefs.h>.
+ */
+extern const size_t _Stack_Allocator_allocate_for_idle_storage_size;
+
+/**
+ * @brief The thread storage areas used by
+ *   _Stack_Allocator_allocate_for_idle_static().
+ *
+ * Application provided via <rtems/confdefs.h>.
+ */
+extern char _Stack_Allocator_allocate_for_idle_storage_areas[];
+
+/**
+ * @brief Allocates the IDLE thread storage from the memory statically
+ *   allocated by <rtems/confdefs.h>.
+ *
+ * @param cpu_index is the index of the CPU for the IDLE thread using this stack.
+ *
+ * @param stack_size[out] is pointer to a size_t object.  On function return, the
+ *   object value is set to the value of
+ *   ::_Stack_Allocator_allocate_for_idle_storage_size.
+ *
+ * @return Returns a pointer to the begin of the allocated task storage area.
+ */
+void *_Stack_Allocator_allocate_for_idle_static(
+  uint32_t  cpu_index,
+  size_t   *storage_size
+);
+
 /**
  * @brief The stack allocator allocate stack for idle thread handler.
  *
@@ -181,6 +231,8 @@ void _Stack_Allocator_do_initialize( void );
 extern const Stack_Allocator_allocate_for_idle
   _Stack_Allocator_allocate_for_idle;
 
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/cpukit/include/rtems/score/thread.h b/cpukit/include/rtems/score/thread.h
index 40fefbc79a..cafa850a94 100644
--- a/cpukit/include/rtems/score/thread.h
+++ b/cpukit/include/rtems/score/thread.h
@@ -1179,13 +1179,6 @@ Thread_Information name##_Information = { \
   } \
 }
 
-/**
- * @brief The idle thread stacks.
- *
- * Provided by the application via <rtems/confdefs.h>.
- */
-extern char _Thread_Idle_stacks[];
-
 #if defined(RTEMS_MULTIPROCESSING)
 /**
  * @brief The configured thread control block.
diff --git a/cpukit/sapi/src/interrtext.c b/cpukit/sapi/src/interrtext.c
index 6ed115f430..e828a82051 100644
--- a/cpukit/sapi/src/interrtext.c
+++ b/cpukit/sapi/src/interrtext.c
@@ -84,7 +84,8 @@ static const char *const internal_error_text[] = {
   "INTERNAL_ERROR_NO_MEMORY_FOR_PER_CPU_DATA",
   "INTERNAL_ERROR_TOO_LARGE_TLS_SIZE",
   "INTERNAL_ERROR_RTEMS_INIT_TASK_CONSTRUCT_FAILED",
-  "INTERNAL_ERROR_IDLE_THREAD_CREATE_FAILED"
+  "INTERNAL_ERROR_IDLE_THREAD_CREATE_FAILED",
+  "INTERNAL_ERROR_NO_MEMORY_FOR_IDLE_TASK_STORAGE"
 };
 
 const char *rtems_internal_error_text( rtems_fatal_code error )
diff --git a/cpukit/score/src/stackallocatorforidle.c b/cpukit/score/src/stackallocatorforidle.c
index c97dde030f..c8c8c0b766 100644
--- a/cpukit/score/src/stackallocatorforidle.c
+++ b/cpukit/score/src/stackallocatorforidle.c
@@ -1,6 +1,15 @@
-/*
- * SPDX-License-Identifier: BSD-2-Clause
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSScoreStack
  *
+ * @brief This source file contains the implementation of
+ *   _Stack_Allocator_allocate_for_idle_static().
+ */
+
+/*
  * Copyright (C) 2021 On-Line Applications Research Corporation (OAR)
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,35 +39,21 @@
 #endif
 
 #include <rtems/score/stack.h>
-#include <rtems/score/thread.h>
 #include <rtems/score/assert.h>
 
-/**
- * @brief Default stack allocator allocate for IDLE threads.
- *
- * The default allocator for IDLE thread stacks gets the memory from a
- * statically allocated area provided via confdefs.h.
- *
- * @param cpu is the index of the CPU for the IDLE thread using this stack.
- *
- * @param stack_size[in] is pointer to a size_t object.  On function
- *   entry, the object contains the size of the stack area to allocate in
- *   bytes.
- *
- * @return Returns the pointer to begin of the allocated stack area.
- */
-static void *_Stack_Allocator_allocate_for_idle_default(
+void *_Stack_Allocator_allocate_for_idle_static(
   uint32_t  cpu_index,
-  size_t   *stack_size
+  size_t   *storage_size
 )
 {
+  size_t size;
+
+  size = _Stack_Allocator_allocate_for_idle_storage_size;
+  *storage_size = size;
 #if defined(RTEMS_SMP)
-  return &_Thread_Idle_stacks[ cpu_index * ( *stack_size ) ];
+  return &_Stack_Allocator_allocate_for_idle_storage_areas[ cpu_index * size ];
 #else
   _Assert( cpu_index == 0 );
-  return &_Thread_Idle_stacks[ 0 ];
+  return &_Stack_Allocator_allocate_for_idle_storage_areas[ 0 ];
 #endif
 }
-
-const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
-        _Stack_Allocator_allocate_for_idle_default;
diff --git a/cpukit/score/src/stackallocatorforidlewkspace.c b/cpukit/score/src/stackallocatorforidlewkspace.c
new file mode 100644
index 0000000000..0864271f07
--- /dev/null
+++ b/cpukit/score/src/stackallocatorforidlewkspace.c
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup RTEMSScoreStack
+ *
+ * @brief This source file contains the implementation of
+ *   _Stack_Allocator_allocate_for_idle_workspace().
+ */
+
+/*
+ * Copyright (C) 2022 embedded brains GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/score/stack.h>
+#include <rtems/score/interr.h>
+#include <rtems/score/wkspace.h>
+
+void *_Stack_Allocator_allocate_for_idle_workspace(
+  uint32_t  unused,
+  size_t   *storage_size
+)
+{
+  void *area;
+
+  (void) unused;
+  area = _Workspace_Allocate( *storage_size );
+
+  if ( area == NULL ) {
+    _Internal_error( INTERNAL_ERROR_NO_MEMORY_FOR_IDLE_TASK_STORAGE );
+  }
+
+  return area;
+}
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index d2037b36f0..04565f910b 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -53,7 +53,10 @@
 
 #include <string.h>
 
-static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
+static void _Thread_Create_idle_for_CPU(
+  Per_CPU_Control *cpu,
+  uintptr_t        storage_size
+)
 {
   Thread_Configuration  config;
   Thread_Control       *idle;
@@ -70,8 +73,7 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
   config.is_fp = CPU_IDLE_TASK_IS_FP;
   config.is_preemptible = true;
   config.stack_free = _Objects_Free_nothing;
-  config.stack_size = _Thread_Idle_stack_size
-    + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE;
+  config.stack_size = storage_size;
 
   /*
    * The IDLE thread stacks may be statically allocated or there may be a
@@ -118,21 +120,28 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
 
 void _Thread_Create_idle( void )
 {
+  uintptr_t storage_size;
 #if defined(RTEMS_SMP)
-  uint32_t cpu_max;
-  uint32_t cpu_index;
+  uint32_t  cpu_max;
+  uint32_t  cpu_index;
+#endif
+
+  storage_size = _TLS_Get_allocation_size() +
+    CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE +
+    _Thread_Idle_stack_size;
 
+#if defined(RTEMS_SMP)
   cpu_max = _SMP_Get_processor_maximum();
 
   for ( cpu_index = 0 ; cpu_index < cpu_max ; ++cpu_index ) {
     Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index );
 
     if ( _Per_CPU_Is_processor_online( cpu ) ) {
-      _Thread_Create_idle_for_CPU( cpu );
+      _Thread_Create_idle_for_CPU( cpu, storage_size );
     }
   }
 #else
-  _Thread_Create_idle_for_CPU( _Per_CPU_Get() );
+  _Thread_Create_idle_for_CPU( _Per_CPU_Get(), storage_size );
 #endif
 
   _CPU_Use_thread_local_storage(
diff --git a/spec/build/cpukit/librtemscpu.yml b/spec/build/cpukit/librtemscpu.yml
index f034f3fadf..a1be70c6da 100644
--- a/spec/build/cpukit/librtemscpu.yml
+++ b/spec/build/cpukit/librtemscpu.yml
@@ -1545,6 +1545,7 @@ source:
 - cpukit/score/src/smpbarrierwait.c
 - cpukit/score/src/stackallocator.c
 - cpukit/score/src/stackallocatorforidle.c
+- cpukit/score/src/stackallocatorforidlewkspace.c
 - cpukit/score/src/stackallocatorfree.c
 - cpukit/score/src/stackallocatorinit.c
 - cpukit/score/src/thread.c
diff --git a/spec/build/testsuites/sptests/grp.yml b/spec/build/testsuites/sptests/grp.yml
index c8f70ed13b..b14eefb145 100644
--- a/spec/build/testsuites/sptests/grp.yml
+++ b/spec/build/testsuites/sptests/grp.yml
@@ -258,6 +258,8 @@ links:
   uid: spfatal34
 - role: build-dependency
   uid: spfatal35
+- role: build-dependency
+  uid: spfatal36
 - role: build-dependency
   uid: spfifo01
 - role: build-dependency
diff --git a/spec/build/testsuites/sptests/spfatal36.yml b/spec/build/testsuites/sptests/spfatal36.yml
new file mode 100644
index 0000000000..9e623e3511
--- /dev/null
+++ b/spec/build/testsuites/sptests/spfatal36.yml
@@ -0,0 +1,19 @@
+SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause
+build-type: test-program
+cflags: []
+copyrights:
+- Copyright (C) 2022 embedded brains GmbH
+cppflags: []
+cxxflags: []
+enabled-by: true
+features: c cprogram
+includes: []
+ldflags: []
+links: []
+source:
+- testsuites/sptests/spfatal36/init.c
+stlib: []
+target: testsuites/sptests/spfatal36.exe
+type: build
+use-after: []
+use-before: []
diff --git a/testsuites/sptests/spfatal36/init.c b/testsuites/sptests/spfatal36/init.c
new file mode 100644
index 0000000000..78725e1d19
--- /dev/null
+++ b/testsuites/sptests/spfatal36/init.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/*
+ * Copyright (C) 2022 embedded brains GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../spfatal_support/spfatal.h"
+
+#include <rtems/sysinit.h>
+#include <rtems/rtems/support.h>
+
+#define FATAL_ERROR_TEST_NAME "36"
+
+#define FATAL_ERROR_DESCRIPTION "failure in idle task storage allocation"
+
+#define FATAL_ERROR_EXPECTED_SOURCE INTERNAL_ERROR_CORE
+
+#define FATAL_ERROR_EXPECTED_ERROR \
+  INTERNAL_ERROR_NO_MEMORY_FOR_IDLE_TASK_STORAGE
+
+static void force_error( void )
+{
+  RTEMS_UNREACHABLE();
+}
+
+static void empty_workspace( void )
+{
+  (void) rtems_workspace_greedy_allocate( NULL, 0 );
+}
+
+RTEMS_SYSINIT_ITEM(
+  empty_workspace,
+  RTEMS_SYSINIT_IDLE_THREADS,
+  RTEMS_SYSINIT_ORDER_FIRST
+);
+
+#include "../spfatal_support/spfatalimpl.h"
diff --git a/testsuites/sptests/spfatal36/spfatal36.doc b/testsuites/sptests/spfatal36/spfatal36.doc
new file mode 100644
index 0000000000..0719e8e01c
--- /dev/null
+++ b/testsuites/sptests/spfatal36/spfatal36.doc
@@ -0,0 +1,11 @@
+This file describes the concepts tested by this test set.
+
+test set name: spfatal36
+
+directives:
+
+  - _Stack_Allocator_allocate_for_idle_workspace()
+
+concepts:
+
+  - Provoke a memory allocation failure in the directive.
diff --git a/testsuites/sptests/spinternalerror02/init.c b/testsuites/sptests/spinternalerror02/init.c
index f94759a99b..475e31e085 100644
--- a/testsuites/sptests/spinternalerror02/init.c
+++ b/testsuites/sptests/spinternalerror02/init.c
@@ -49,7 +49,7 @@ static void test_internal_error_text(void)
   } while ( text != text_last );
 
   rtems_test_assert(
-    error - 3 == INTERNAL_ERROR_IDLE_THREAD_CREATE_FAILED
+    error - 3 == INTERNAL_ERROR_NO_MEMORY_FOR_IDLE_TASK_STORAGE
   );
 }
 
diff --git a/testsuites/sptests/spstkalloc02/init.c b/testsuites/sptests/spstkalloc02/init.c
index 3613a6a563..7fee4615ad 100644
--- a/testsuites/sptests/spstkalloc02/init.c
+++ b/testsuites/sptests/spstkalloc02/init.c
@@ -44,6 +44,7 @@ const char rtems_test_name[] = "SPSTKALLOC 2";
 #include <stdio.h>
 #include <inttypes.h>
 
+#include <rtems/malloc.h>
 #include <rtems/score/heapimpl.h>
 
 #define TASK_COUNT 5
@@ -56,6 +57,8 @@ static void task_stack_init(size_t stack_space_size);
 
 static void *task_stack_allocate(size_t stack_size);
 
+static void *task_stack_allocate_for_idle(uint32_t unused, size_t *stack_size);
+
 static void task_stack_free(void *addr);
 
 static void print_info(void)
@@ -149,6 +152,7 @@ static rtems_task Init(rtems_task_argument argument)
 
 #define CONFIGURE_TASK_STACK_ALLOCATOR_INIT task_stack_init
 #define CONFIGURE_TASK_STACK_ALLOCATOR task_stack_allocate
+#define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE task_stack_allocate_for_idle
 #define CONFIGURE_TASK_STACK_DEALLOCATOR task_stack_free
 #define CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
 #define CONFIGURE_TASK_STACK_FROM_ALLOCATOR(stack_size) \
@@ -183,6 +187,15 @@ static void *task_stack_allocate(size_t stack_size)
   return _Heap_Allocate(&task_stack_heap, stack_size);
 }
 
+static void *task_stack_allocate_for_idle(uint32_t unused, size_t *stack_size)
+{
+  return rtems_heap_allocate_aligned_with_boundary(
+    *stack_size,
+    CPU_STACK_ALIGNMENT,
+    0
+  );
+}
+
 static void task_stack_free(void *addr)
 {
   _Heap_Free(&task_stack_heap, addr);
diff --git a/testsuites/sptests/sptls02/init.cc b/testsuites/sptests/sptls02/init.cc
index 39fc2a2a24..b453ef3f62 100644
--- a/testsuites/sptests/sptls02/init.cc
+++ b/testsuites/sptests/sptls02/init.cc
@@ -48,7 +48,7 @@ alignas(256) static thread_local long a256 = 256;
 
 static thread_local long i0;
 
-alignas(512) static thread_local long a512;
+alignas(RTEMS_MINIMUM_STACK_SIZE) static thread_local long a;
 
 int seven()
 {
@@ -61,7 +61,7 @@ static void clobber()
 	i123 = 0xdead0001;
 	a256 = 0xdead0002;
 	i0 = 0xdead0003;
-	a512 = 0xdead0004;
+	a = 0xdead0004;
 }
 
 static long f456(bool clobber)
@@ -173,8 +173,8 @@ static void checkTLSValues()
 	RTEMS_OBFUSCATE_VARIABLE(addr);
 	rtems_test_assert((addr % 256) == 0);
 	rtems_test_assert(i0 == 0);
-	rtems_test_assert(a512 == 0);
-	addr = reinterpret_cast<uintptr_t>(&a512);
+	rtems_test_assert(a == 0);
+	addr = reinterpret_cast<uintptr_t>(&a);
 	RTEMS_OBFUSCATE_VARIABLE(addr);
 	rtems_test_assert((addr % 512) == 0);
 	rtems_test_assert(f456(false) == 456);
diff --git a/testsuites/validation/ts-default.h b/testsuites/validation/ts-default.h
index 6e77496b90..be26055c8b 100644
--- a/testsuites/validation/ts-default.h
+++ b/testsuites/validation/ts-default.h
@@ -317,7 +317,10 @@ RTEMS_SCHEDULER_PRIORITY( a, 64 );
 #define CONFIGURE_IDLE_TASK_STACK_SIZE TEST_IDLE_STACK_SIZE
 
 static char test_idle_stacks[ CONFIGURE_MAXIMUM_PROCESSORS ][
-  ( TEST_IDLE_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE )
+  RTEMS_ALIGN_UP(
+    MAX_TLS_SIZE + TEST_IDLE_STACK_SIZE + CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE,
+    CPU_INTERRUPT_STACK_ALIGNMENT
+  )
 ]
 RTEMS_ALIGNED( CPU_INTERRUPT_STACK_ALIGNMENT )
 RTEMS_SECTION( ".rtemsstack.idle" );
diff --git a/testsuites/validation/ts-fatal-sysinit.h b/testsuites/validation/ts-fatal-sysinit.h
index 09d86d02ea..7a2f86ecca 100644
--- a/testsuites/validation/ts-fatal-sysinit.h
+++ b/testsuites/validation/ts-fatal-sysinit.h
@@ -133,6 +133,8 @@ RTEMS_SYSINIT_ITEM(
   { .fatal = FatalInitialExtension }, \
   { .fatal = TestSuiteFatalExtension }
 
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE
+
 #if !defined(CONFIGURE_RTEMS_INIT_TASKS_TABLE)
 
 #define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION
diff --git a/testsuites/validation/ts-idle.h b/testsuites/validation/ts-idle.h
index 071209b5ef..04feaa096d 100644
--- a/testsuites/validation/ts-idle.h
+++ b/testsuites/validation/ts-idle.h
@@ -72,6 +72,10 @@ static const T_config test_config = {
 #define CONFIGURE_INITIAL_EXTENSIONS \
   { .fatal = FatalInitialExtension }
 
+#ifndef CONFIGURE_IDLE_TASK_STORAGE_SIZE
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE
+#endif
+
 #define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION
 
 void *IdleBody( uintptr_t ignored )
diff --git a/testsuites/validation/ts-validation-acfg-0.c b/testsuites/validation/ts-validation-acfg-0.c
index e1144dd95d..f0fd359007 100644
--- a/testsuites/validation/ts-validation-acfg-0.c
+++ b/testsuites/validation/ts-validation-acfg-0.c
@@ -72,6 +72,8 @@
 
 const char rtems_test_name[] = "ValidationAcfg0";
 
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE
+
 #define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION
 
 void *IdleBody( uintptr_t ignored )
diff --git a/testsuites/validation/ts-validation-acfg-1.c b/testsuites/validation/ts-validation-acfg-1.c
index 863a672b23..b12ccb928b 100644
--- a/testsuites/validation/ts-validation-acfg-1.c
+++ b/testsuites/validation/ts-validation-acfg-1.c
@@ -94,6 +94,8 @@ static void Init( rtems_task_argument arg )
 
 #define CONFIGURE_DISABLE_BSP_SETTINGS
 
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE
+
 #define CONFIGURE_MAXIMUM_TASKS 1
 
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
diff --git a/testsuites/validation/ts-validation-io-kernel.c b/testsuites/validation/ts-validation-io-kernel.c
index 83234ecfff..db44303890 100644
--- a/testsuites/validation/ts-validation-io-kernel.c
+++ b/testsuites/validation/ts-validation-io-kernel.c
@@ -138,6 +138,8 @@ static void *IdleBody( uintptr_t ignored )
 
 #define CONFIGURE_SCHEDULER_TABLE_ENTRIES { }
 
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE RTEMS_MINIMUM_STACK_SIZE
+
 #define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION
 
 #define CONFIGURE_IDLE_TASK_BODY IdleBody
diff --git a/testsuites/validation/ts-validation-tls-1.c b/testsuites/validation/ts-validation-tls-1.c
index b9b4adc31e..d05f9e1d08 100644
--- a/testsuites/validation/ts-validation-tls-1.c
+++ b/testsuites/validation/ts-validation-tls-1.c
@@ -68,6 +68,9 @@
 
 const char rtems_test_name[] = "ValidationTls1";
 
+#define CONFIGURE_IDLE_TASK_STORAGE_SIZE \
+  ( RTEMS_MINIMUM_STACK_SIZE + 4096 )
+
 #include "ts-idle.h"
 
 /** @} */
-- 
2.35.3



More information about the devel mailing list