[RTEMS 5 v2] Add support for IDLE Thread stack allocator
Joel Sherrill
joel at rtems.org
Tue Oct 5 18:43:12 UTC 2021
Add a stack allocator hook specifically for allocation of IDLE thread stacks.
This allows the user to decide if IDLE thread stacks are statically allocated
or handled by the same custom allocator mechanism as other thread stacks.
Closes #4520.
---
cpukit/Makefile.am | 1 +
cpukit/include/rtems/confdefs/percpu.h | 18 ++-
cpukit/include/rtems/confdefs/wkspace.h | 22 ++++
cpukit/include/rtems/config.h | 3 +
cpukit/include/rtems/score/stack.h | 42 +++++++
cpukit/score/src/stackallocatorforidle.c | 36 ++++++
cpukit/score/src/threadcreateidle.c | 24 +++-
testsuites/sptests/Makefile.am | 9 ++
testsuites/sptests/configure.ac | 1 +
testsuites/sptests/spstkalloc03/init.c | 103 ++++++++++++++++++
.../sptests/spstkalloc03/spstkalloc03.doc | 19 ++++
.../sptests/spstkalloc03/spstkalloc03.scn | 2 +
12 files changed, 272 insertions(+), 8 deletions(-)
create mode 100644 cpukit/score/src/stackallocatorforidle.c
create mode 100644 testsuites/sptests/spstkalloc03/init.c
create mode 100644 testsuites/sptests/spstkalloc03/spstkalloc03.doc
create mode 100644 testsuites/sptests/spstkalloc03/spstkalloc03.scn
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 18eda95543..202cf3c346 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -930,6 +930,7 @@ librtemscpu_a_SOURCES += score/src/schedulercbssetparameters.c
librtemscpu_a_SOURCES += score/src/schedulercbsreleasejob.c
librtemscpu_a_SOURCES += score/src/schedulercbsunblock.c
librtemscpu_a_SOURCES += score/src/stackallocator.c
+librtemscpu_a_SOURCES += score/src/stackallocatorforidle.c
librtemscpu_a_SOURCES += score/src/pheapallocate.c
librtemscpu_a_SOURCES += score/src/pheapextend.c
librtemscpu_a_SOURCES += score/src/pheapfree.c
diff --git a/cpukit/include/rtems/confdefs/percpu.h b/cpukit/include/rtems/confdefs/percpu.h
index f3a9a4f3e7..b7baebea05 100644
--- a/cpukit/include/rtems/confdefs/percpu.h
+++ b/cpukit/include/rtems/confdefs/percpu.h
@@ -133,11 +133,19 @@ RTEMS_DEFINE_GLOBAL_SYMBOL(
const size_t _Thread_Idle_stack_size = CONFIGURE_IDLE_TASK_STACK_SIZE;
-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" );
+/*
+ * 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)
diff --git a/cpukit/include/rtems/confdefs/wkspace.h b/cpukit/include/rtems/confdefs/wkspace.h
index 484dde20ea..22a4c4c063 100644
--- a/cpukit/include/rtems/confdefs/wkspace.h
+++ b/cpukit/include/rtems/confdefs/wkspace.h
@@ -132,12 +132,14 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
#if defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
&& defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
+ /* Custom allocator may or may not use the work space. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
const bool _Stack_Allocator_avoids_workspace = true;
#else
const bool _Stack_Allocator_avoids_workspace = false;
#endif
+ /* Custom allocator may or may not need initialization. */
#ifdef CONFIGURE_TASK_STACK_ALLOCATOR_INIT
const Stack_Allocator_initialize _Stack_Allocator_initialize =
CONFIGURE_TASK_STACK_ALLOCATOR_INIT;
@@ -145,14 +147,34 @@ const uintptr_t _Stack_Space_size = _CONFIGURE_STACK_SPACE_SIZE;
const Stack_Allocator_initialize _Stack_Allocator_initialize = NULL;
#endif
+ /* Custom allocator must include allocate and free */
const Stack_Allocator_allocate _Stack_Allocator_allocate =
CONFIGURE_TASK_STACK_ALLOCATOR;
const Stack_Allocator_free _Stack_Allocator_free =
CONFIGURE_TASK_STACK_DEALLOCATOR;
+
+ /* custom IDLE thread stacks allocator */
+ #ifdef CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE
+ const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+ CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE;
+ #endif
+
+/*
+ * Must provide both a custom stack allocator and deallocator
+ */
#elif defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
|| defined(CONFIGURE_TASK_STACK_DEALLOCATOR)
#error "CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR must be both defined or both undefined"
+
+/*
+ * If the application wants to provide an IDLE threads stack allocator, it
+ * must also provide a custom allocator/deallocator for user thread stacks.
+ */
+#elif (!defined(CONFIGURE_TASK_STACK_ALLOCATOR) \
+ && !defined(CONFIGURE_TASK_STACK_DEALLOCATOR)) \
+ && defined(CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE)
+ #error "CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE can only be provided if both CONFIGURE_TASK_STACK_ALLOCATOR and CONFIGURE_TASK_STACK_DEALLOCATOR are provided"
#endif
#ifdef CONFIGURE_DIRTY_MEMORY
diff --git a/cpukit/include/rtems/config.h b/cpukit/include/rtems/config.h
index e82c7abf11..a826581658 100644
--- a/cpukit/include/rtems/config.h
+++ b/cpukit/include/rtems/config.h
@@ -129,6 +129,9 @@ uint32_t rtems_configuration_get_maximum_extensions( void );
#define rtems_configuration_get_stack_free_hook() \
(_Stack_Allocator_free)
+#define rtems_configuration_get_stack_allocate_for_idle_hook() \
+ (_Stack_Allocator_allocate_for_idle)
+
/**
* This macro assists in accessing the field which indicates whether
* RTEMS is responsible for zeroing the Executive Workspace.
diff --git a/cpukit/include/rtems/score/stack.h b/cpukit/include/rtems/score/stack.h
index df1df74867..6b20d4b977 100644
--- a/cpukit/include/rtems/score/stack.h
+++ b/cpukit/include/rtems/score/stack.h
@@ -23,6 +23,7 @@
#define _RTEMS_SCORE_STACK_H
#include <rtems/score/basedefs.h>
+#include <rtems/score/percpu.h>
#ifdef __cplusplus
extern "C" {
@@ -81,6 +82,23 @@ typedef void *( *Stack_Allocator_allocate )( size_t stack_size );
*/
typedef void ( *Stack_Allocator_free )( void *addr );
+/**
+ * @brief Stack allocator allocate for idle handler.
+ *
+ * The allocate for idle handler is optional even when the user thread stack
+ * allocator and deallocator are configured.
+ *
+ * @param cpu Information for the CPU for the IDLE thread using this stack
+ * @param stack_size The size of the stack area to allocate in bytes.
+ *
+ * @retval NULL Not enough memory.
+ * @retval other Pointer to begin of stack area.
+ */
+typedef void *( *Stack_Allocator_allocate_for_idle )(
+ Per_CPU_Control *cpu,
+ size_t stack_size
+);
+
/**
* @brief The minimum stack size.
*
@@ -124,6 +142,30 @@ extern const Stack_Allocator_allocate _Stack_Allocator_allocate;
extern const Stack_Allocator_free _Stack_Allocator_free;
/** @} */
+/**
+ * @brief The stack allocator allocate stack for idle thread handler.
+ *
+ * Application provided via <rtems/confdefs.h>.
+ */
+extern const Stack_Allocator_allocate_for_idle
+ _Stack_Allocator_allocate_for_idle;
+
+/**
+ * @brief Default stack allocator allocate for idle handler.
+ *
+ * The allocate for idle handler is optional even when the user thread stack
+ * allocator and deallocator are configured.
+ *
+ * @param cpu Information for the CPU for the IDLE thread using this stack
+ * @param stack_size The size of the stack area to allocate in bytes.
+ *
+ * @retval NULL Not enough memory.
+ * @retval other Pointer to begin of stack area.
+ */
+void *_Stack_Allocator_allocate_for_idle_default(
+ Per_CPU_Control *cpu,
+ size_t stack_size
+);
#ifdef __cplusplus
}
diff --git a/cpukit/score/src/stackallocatorforidle.c b/cpukit/score/src/stackallocatorforidle.c
new file mode 100644
index 0000000000..d33cd4dbf5
--- /dev/null
+++ b/cpukit/score/src/stackallocatorforidle.c
@@ -0,0 +1,36 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (C) 2021 OAR Corporation
+ *
+ * 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/wkspace.h>
+
+const Stack_Allocator_allocate_for_idle _Stack_Allocator_allocate_for_idle =
+ _Stack_Allocator_allocate_for_idle_default;
diff --git a/cpukit/score/src/threadcreateidle.c b/cpukit/score/src/threadcreateidle.c
index 1e18ad07cc..d9765ddb9a 100644
--- a/cpukit/score/src/threadcreateidle.c
+++ b/cpukit/score/src/threadcreateidle.c
@@ -28,6 +28,18 @@
#include <string.h>
+/*
+ * Default allocator for IDLE thread stacks gets the memory from a
+ * statically allocated area provided via confdefs.h.
+ */
+void *_Stack_Allocator_allocate_for_idle_default(
+ Per_CPU_Control *cpu,
+ size_t stack_size
+)
+{
+ return &_Thread_Idle_stacks[ _Per_CPU_Get_index( cpu ) * stack_size ];
+}
+
static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
{
Thread_Configuration config;
@@ -53,9 +65,15 @@ static void _Thread_Create_idle_for_CPU( Per_CPU_Control *cpu )
config.is_preemptible = true;
config.stack_size = _Thread_Idle_stack_size
+ CPU_IDLE_TASK_IS_FP * CONTEXT_FP_SIZE;
- config.stack_area = &_Thread_Idle_stacks[
- _Per_CPU_Get_index( cpu ) * config.stack_size
- ];
+
+ /*
+ * The IDLE thread stacks may be statically allocated or there may be a
+ * custom allocator provided just as with user threads.
+ */
+ config.stack_area = (*_Stack_Allocator_allocate_for_idle)(
+ _Per_CPU_Get_index( cpu ),
+ config.stack_size
+ );
/*
* The entire workspace is zeroed during its initialization. Thus, all
diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am
index 62bb1aa685..1b23d1eb85 100644
--- a/testsuites/sptests/Makefile.am
+++ b/testsuites/sptests/Makefile.am
@@ -1783,6 +1783,15 @@ spstkalloc02_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc02) \
$(support_includes)
endif
+if TEST_spstkalloc03
+sp_tests += spstkalloc03
+sp_screens += spstkalloc03/spstkalloc03.scn
+sp_docs += spstkalloc03/spstkalloc03.doc
+spstkalloc03_SOURCES = spstkalloc03/init.c
+spstkalloc03_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_spstkalloc03) \
+ $(support_includes)
+endif
+
if TEST_spsysinit01
sp_tests += spsysinit01
sp_screens += spsysinit01/spsysinit01.scn
diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac
index 9476e3b0d7..a45fe647dd 100644
--- a/testsuites/sptests/configure.ac
+++ b/testsuites/sptests/configure.ac
@@ -228,6 +228,7 @@ RTEMS_TEST_CHECK([spsize])
RTEMS_TEST_CHECK([spstdthreads01])
RTEMS_TEST_CHECK([spstkalloc])
RTEMS_TEST_CHECK([spstkalloc02])
+RTEMS_TEST_CHECK([spstkalloc03])
RTEMS_TEST_CHECK([spsysinit01])
RTEMS_TEST_CHECK([spsyslock01])
RTEMS_TEST_CHECK([sptask_err01])
diff --git a/testsuites/sptests/spstkalloc03/init.c b/testsuites/sptests/spstkalloc03/init.c
new file mode 100644
index 0000000000..2cfd418584
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/init.c
@@ -0,0 +1,103 @@
+/*
+ * COPYRIGHT (c) 2021.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <tmacros.h>
+
+#include <rtems/score/percpu.h>
+
+const char rtems_test_name[] = "SPSTKALLOC 3";
+
+static int thread_stacks_count = 0xff;
+
+static rtems_task Init(
+ rtems_task_argument ignored
+)
+{
+ rtems_print_printer_fprintf_putc(&rtems_test_printer);
+ TEST_BEGIN();
+ rtems_test_assert(thread_stacks_count == 2);
+ TEST_END();
+ rtems_test_exit( 0 );
+}
+
+static uint8_t stack_memory[RTEMS_MINIMUM_STACK_SIZE * 4];
+
+static int stack_offset_next;
+
+static void *allocate_helper(size_t size)
+{
+ size_t next;
+ void *alloc;
+
+ next = stack_offset_next + size;
+ rtems_test_assert( next < sizeof(stack_memory) );
+
+ alloc = &stack_memory[stack_offset_next];
+ stack_offset_next = next;
+ return alloc;
+}
+
+static void thread_stacks_initialize(size_t stack_space_size)
+{
+ rtems_test_assert(thread_stacks_count == 0xff);
+ thread_stacks_count = 0;
+}
+
+static void *thread_stacks_allocate(size_t stack_size)
+{
+ rtems_test_assert(thread_stacks_count == 1);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+static void thread_stacks_free(void *addr)
+{
+ rtems_test_assert(false);
+}
+
+static void *thread_stacks_allocate_for_idle(
+ Per_CPU_Control *cpu,
+ size_t stack_size
+)
+{
+ rtems_test_assert(thread_stacks_count == 0);
+ thread_stacks_count++;
+ return allocate_helper(stack_size);
+}
+
+/*
+ * Configure the thread stack allocators to not use the workspace. This should
+ * eliminate all uses of the Workspace for most BSPs.
+ */
+#define CONFIGURE_TASK_STACK_ALLOCATOR_AVOIDS_WORK_SPACE
+#define CONFIGURE_TASK_STACK_ALLOCATOR_INIT thread_stacks_initialize
+#define CONFIGURE_TASK_STACK_ALLOCATOR thread_stacks_allocate
+#define CONFIGURE_TASK_STACK_DEALLOCATOR thread_stacks_free
+#define CONFIGURE_TASK_STACK_ALLOCATOR_FOR_IDLE thread_stacks_allocate_for_idle
+
+
+/* NOTICE: the clock driver is explicitly disabled */
+#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS 1
+
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_FLOATING_POINT
+
+#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
+
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/sptests/spstkalloc03/spstkalloc03.doc b/testsuites/sptests/spstkalloc03/spstkalloc03.doc
new file mode 100644
index 0000000000..797716b623
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/spstkalloc03.doc
@@ -0,0 +1,19 @@
+# COPYRIGHT (c) 2021.
+# On-Line Applications Research Corporation (OAR).
+#
+# The license and distribution terms for this file may be
+# found in the file LICENSE in this distribution or at
+# http://www.rtems.org/license/LICENSE.
+#
+
+This file describes the directives and concepts tested by this test set.
+
+test set name: spstkalloc03
+
+directives:
+
+concepts:
+
++ Ensure that the task stack allocator including IDLE thread
+ stack allocator works.
+
diff --git a/testsuites/sptests/spstkalloc03/spstkalloc03.scn b/testsuites/sptests/spstkalloc03/spstkalloc03.scn
new file mode 100644
index 0000000000..45c67ef1fb
--- /dev/null
+++ b/testsuites/sptests/spstkalloc03/spstkalloc03.scn
@@ -0,0 +1,2 @@
+*** BEGIN OF TEST SPSTKALLOC 3 ***
+*** END OF TEST SPSTKALLOC 3 ***
--
2.24.4
More information about the devel
mailing list