<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Sep 2, 2020 at 11:09 AM Sebastian Huber <<a href="mailto:sebastian.huber@embedded-brains.de">sebastian.huber@embedded-brains.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">In contrast to rtems_task_create() this function creates a task with a<br>
user-provided task storage area.  The new create function uses a<br>
configuration structure instead of individual parameters.<br>
<br>
Add RTEMS_TASK_STORAGE_ALIGNMENT to define the recommended alignment of<br>
a task storage area.<br>
<br>
Add RTEMS_TASK_STORAGE_SIZE() to calculate the recommended size of a<br>
task storage area based on the task attributes and the size dedicated to<br>
the task stack and thread-local storage.  This macro may allow future<br>
extensions without breaking the API.<br>
<br>
Update #3959.<br>
---<br>
<br>
v2:<br>
<br>
Rename function from rtems_task_build() to<br>
rtems_task_create_from_config().  Add RTEMS_TASK_STORAGE_ALIGNMENT and<br>
RTEMS_TASK_STORAGE_SIZE().  Improve documentation.<br>
<br>
 cpukit/Makefile.am                      |   1 +<br>
 cpukit/include/rtems/rtems/tasks.h      | 124 +++++++++++<br>
 cpukit/include/rtems/rtems/tasksimpl.h  |  11 +<br>
 cpukit/rtems/src/taskcreate.c           | 278 +++++-------------------<br>
 cpukit/rtems/src/taskcreatefromconfig.c | 274 +++++++++++++++++++++++<br>
 testsuites/sptests/sp01/init.c          |  24 +-<br>
 testsuites/sptests/sp01/sp01.doc        |   1 +<br>
 testsuites/sptests/sp01/system.h        |   2 +-<br>
 8 files changed, 479 insertions(+), 236 deletions(-)<br>
 create mode 100644 cpukit/rtems/src/taskcreatefromconfig.c<br>
<br>
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am<br>
index e5009e53c9..caa6a9efe6 100644<br>
--- a/cpukit/Makefile.am<br>
+++ b/cpukit/Makefile.am<br>
@@ -787,6 +787,7 @@ librtemscpu_a_SOURCES += rtems/src/statustoerrno.c<br>
 librtemscpu_a_SOURCES += rtems/src/systemeventreceive.c<br>
 librtemscpu_a_SOURCES += rtems/src/systemeventsend.c<br>
 librtemscpu_a_SOURCES += rtems/src/taskcreate.c<br>
+librtemscpu_a_SOURCES += rtems/src/taskcreatefromconfig.c<br>
 librtemscpu_a_SOURCES += rtems/src/taskdelete.c<br>
 librtemscpu_a_SOURCES += rtems/src/taskexit.c<br>
 librtemscpu_a_SOURCES += rtems/src/taskgetaffinity.c<br>
diff --git a/cpukit/include/rtems/rtems/tasks.h b/cpukit/include/rtems/rtems/tasks.h<br>
index 12c323e60e..a183dcafed 100644<br>
--- a/cpukit/include/rtems/rtems/tasks.h<br>
+++ b/cpukit/include/rtems/rtems/tasks.h<br>
@@ -21,6 +21,7 @@<br>
 #include <rtems/rtems/attr.h><br>
 #include <rtems/rtems/status.h><br>
 #include <rtems/rtems/types.h><br>
+#include <rtems/score/context.h><br>
 #include <rtems/score/smp.h><br>
<br>
 #ifdef __cplusplus<br>
@@ -164,6 +165,129 @@ rtems_status_code rtems_task_create(<br>
   rtems_id            *id<br>
 );<br>
<br>
+/**<br>
+ * @brief Returns the recommended task storage area size for the specified size<br>
+ *   and task attributes.<br>
+ *<br>
+ * @param _size is the size dedicated to the task stack and thread-local<br>
+ *   storage.<br></blockquote><div><br></div><div>How does the user get the TLS size? </div><div><br></div><div>Need advice on that. Seems hard to get at compile time since it is a link</div><div>time aggregation. </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+ *<br>
+ * @param _attributes is the attribute set of the task using the storage area.<br>
+ *<br>
+ * @return The recommended task storage area size is returned calculated from<br>
+ *   the input parameters.<br>
+ *<br>
+ * @see rtems_task_config<br>
+ */<br>
+#define RTEMS_TASK_STORAGE_SIZE( _size, _attributes ) \<br>
+  ( ( _size ) + \<br>
+    ( ( ( _attributes ) & RTEMS_FLOATING_POINT ) != 0 ? CONTEXT_FP_SIZE : 0 ) )<br></blockquote><div><br></div><div>If the architecture requires all threads to be FP, I don't think this will work.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+/**<br>
+ * @brief This variable attribute defines the recommended alignment of a task<br>
+ *   storage area.<br>
+ *<br>
+ * @see rtems_task_config<br>
+ */<br>
+#define RTEMS_TASK_STORAGE_ALIGNMENT RTEMS_ALIGNED( CPU_STACK_ALIGNMENT )<br>
<br></blockquote><div>Good. I assume the stack comes off the lower address range. Will </div><div>the TLS and FP areas have sufficient alignment? Is that accounted for?</div><div><br></div><div>I can't speak to generic TLS alignment but seems like cache alignment </div><div>is what the linker script would aim for.</div><div><br></div><div>FP context may have to be double aligned on many architectures.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+/**<br>
+ * @brief This structure defines the configuration of a task created by<br>
+ *   rtems_task_create_from_config().<br>
+ */<br>
+typedef struct {<br>
+  /**<br>
+   * @brief This member defines the name of the task.<br>
+   */<br>
+  rtems_name name;<br>
+<br>
+  /**<br>
+   * @brief This member defines initial priority of the task.<br>
+   */<br>
+  rtems_task_priority initial_priority;<br>
+<br>
+  /**<br>
+   * @brief This member shall point to the task storage area begin.<br>
+   *<br>
+   * The task storage area will contain the task stack, the thread-local<br>
+   * storage, and, on some architectures, the floating-point context.<br></blockquote><div><br></div><div>What does this mean? I think most architectures treat the areas as</div><div>separate (FP not in integer context) and some require all tasks to be </div><div>FP. This seems inaccurate.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+   *<br>
+   * There are no alignment requirements for the task storage area.  To avoid<br>
+   * memory waste, use the ::RTEMS_TASK_STORAGE_ALIGNMENT variable attribute to<br>
+   * enforce the recommended alignment of the task storage area.<br>
+   */<br>
+  void *storage_area;<br>
+<br>
+  /**<br>
+   * @brief This member defines size of the task storage area in bytes.<br>
+   *<br>
+   * Use the RTEMS_TASK_STORAGE_SIZE() macro to determine the recommended task<br>
+   * storage area size.<br>
+   */<br>
+  size_t storage_size;<br>
+<br>
+  /**<br>
+   * @brief This member defines the optional handler to free the task storage<br>
+   *   area.<br>
+   *<br>
+   * It is called when the task building aborts due to a failed task create<br>
+   * extension or the task is deleted.  It is called from task context under<br>
+   * protection of the object allocator lock.  It is allowed to call free() in<br>
+   * this handler.  The handler may be NULL.<br>
+   */<br>
+  void ( *storage_free )( void * );<br></blockquote><div><br></div><div>Is it not called when the thread is deleted? </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+  /**<br>
+   * @brief This member defines the initial modes of the task.<br>
+   */<br>
+  rtems_mode initial_modes;<br>
+<br>
+  /**<br>
+   * @brief This member defines the attributes of the task.<br>
+   */<br>
+  rtems_attribute attributes;<br>
+} rtems_task_config;<br>
+<br>
+/**<br>
+ * @brief Creates a task according to the specified configuration.<br>
+ *<br>
+ * In contrast to tasks created by rtems_task_create(), the tasks created by<br>
+ * this directive use a user-provided task storage area (contains the task<br>
+ * stack).<br></blockquote><div><br></div><div>Drop () and say which contains the task stack.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+ * <br>
+ * It is not recommended to mix rtems_task_create() and<br>
+ * rtems_task_create_from_config() in an application.  This directive is<br>
+ * intended for applications which do not want to use the RTEMS Workspace and<br>
+ * instead statically allocate all operating system resources.  The stack space<br>
+ * estimate done by <rtems/confdefs.h> assumes that all tasks are created by<br>
+ * rtems_task_create().  The estimate can be adjusted to take user-provided task<br>
+ * storage areas into account through the ::CONFIGURE_MEMORY_OVERHEAD<br>
+ * application configuration option or a custom task stack allocator, see<br>
+ * ::CONFIGURE_TASK_STACK_ALLOCATOR.<br></blockquote><div><br></div><div>CONFIGURE_MEMORY_OVERHEAD would have to be a negative number to</div><div>make this work. Is this explained or is there some magic I am missing?</div><div><br></div><div>CONFIGURE_MEMORY_OVERHEAD is intended as a backdoor if the</div><div>confdefs.h memory calculation is too low. It is not intended for general</div><div>use like this.</div><div><br></div><div>I would rather see something like "configure build tasks" and just subtract</div><div>that from maximum threads before multiplying by minimum stack size.</div><div>This avoids the user having to add up all their statically allocated stack</div><div>sizes.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+ *<br>
+ * @param config is the task configuration.<br>
+ *<br>
+ * @param[out] id is the pointer to an object identifier variable.  The object<br>
+ *   identifier of the created task will be stored in this variable, in case of<br>
+ *   a successful operation.<br>
+ *<br>
+ * @retval RTEMS_SUCCESSFUL Successful operation.<br>
+ *<br>
+ * @retval RTEMS_INVALID_ADDRESS The id parameter is @c NULL.<br>
+ *<br>
+ * @retval RTEMS_INVALID_NAME The task name is invalid.<br>
+ *<br>
+ * @retval RTEMS_INVALID_PRIORITY The initial priority of the task is invalid.<br>
+ *<br>
+ * @retval RTEMS_TOO_MANY No task is available.<br>
+ *<br>
+ * @retval RTEMS_UNSATISFIED A task create extension failed.<br>
+ */<br>
+rtems_status_code rtems_task_create_from_config(<br>
+  const rtems_task_config *config,<br>
+  rtems_id                *id<br>
+);<br>
+<br>
 /**<br>
  * @brief RTEMS Task Name to Id<br>
  *<br>
diff --git a/cpukit/include/rtems/rtems/tasksimpl.h b/cpukit/include/rtems/rtems/tasksimpl.h<br>
index c9544f8c27..a39113a283 100644<br>
--- a/cpukit/include/rtems/rtems/tasksimpl.h<br>
+++ b/cpukit/include/rtems/rtems/tasksimpl.h<br>
@@ -42,6 +42,17 @@ extern "C" {<br>
  */<br>
 void _RTEMS_tasks_Initialize_user_tasks( void );<br>
<br>
+typedef void ( *RTEMS_tasks_Prepare_stack )(<br>
+  Thread_Configuration *,<br>
+  const rtems_task_config *<br>
+);<br>
+<br>
+rtems_status_code _RTEMS_tasks_Create(<br>
+  const rtems_task_config   *config,<br>
+  rtems_id                  *id,<br>
+  RTEMS_tasks_Prepare_stack  prepare_stack<br>
+);<br>
+<br>
 RTEMS_INLINE_ROUTINE Thread_Control *_RTEMS_tasks_Allocate(void)<br>
 {<br>
   _Objects_Allocator_lock();<br>
diff --git a/cpukit/rtems/src/taskcreate.c b/cpukit/rtems/src/taskcreate.c<br>
index 5486ac9b6e..1d9a4546e8 100644<br>
--- a/cpukit/rtems/src/taskcreate.c<br>
+++ b/cpukit/rtems/src/taskcreate.c<br>
@@ -1,17 +1,36 @@<br>
+/* SPDX-License-Identifier: BSD-2-Clause */<br>
+<br>
 /**<br>
- *  @file<br>
+ * @file<br>
+ *<br>
+ * @ingroup ClassicTasks<br>
  *<br>
- *  @brief RTEMS Task Create<br>
- *  @ingroup ClassicTasks<br>
+ * @brief RTEMS Task Create<br>
  */<br>
<br>
 /*<br>
- *  COPYRIGHT (c) 1989-2014,2016.<br>
- *  On-Line Applications Research Corporation (OAR).<br>
+ * Copyright (C) 2020 embedded brains GmbH (<a href="http://www.embedded-brains.de" rel="noreferrer" target="_blank">http://www.embedded-brains.de</a>)<br>
  *<br>
- *  The license and distribution terms for this file may be<br>
- *  found in the file LICENSE in this distribution or at<br>
- *  <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ * Redistribution and use in source and binary forms, with or without<br>
+ * modification, are permitted provided that the following conditions<br>
+ * are met:<br>
+ * 1. Redistributions of source code must retain the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer.<br>
+ * 2. Redistributions in binary form must reproduce the above copyright<br>
+ *    notice, this list of conditions and the following disclaimer in the<br>
+ *    documentation and/or other materials provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"<br>
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br>
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br>
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE<br>
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR<br>
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS<br>
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN<br>
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)<br>
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE<br>
+ * POSSIBILITY OF SUCH DAMAGE.<br>
  */<br>
<br>
 #ifdef HAVE_CONFIG_H<br>
@@ -19,20 +38,24 @@<br>
 #endif<br>
<br>
 #include <rtems/rtems/tasksimpl.h><br>
-#include <rtems/rtems/attrimpl.h><br>
-#include <rtems/rtems/eventimpl.h><br>
-#include <rtems/rtems/modesimpl.h><br>
-#include <rtems/rtems/support.h><br>
-#include <rtems/score/apimutex.h><br>
-#include <rtems/score/schedulerimpl.h><br>
 #include <rtems/score/stackimpl.h><br>
-#include <rtems/score/sysstate.h><br>
-#include <rtems/score/threadimpl.h><br>
-#include <rtems/score/userextimpl.h><br>
-#include <rtems/sysinit.h><br>
<br>
 #include <string.h><br>
<br>
+static void _RTEMS_tasks_Allocate_and_prepare_stack(<br>
+  Thread_Configuration    *thread_config,<br>
+  const rtems_task_config *config<br>
+)<br>
+{<br>
+  size_t size;<br>
+<br>
+  thread_config->stack_free = _Stack_Free;<br>
+  size = _Stack_Ensure_minimum( config->storage_size );<br>
+  size = _Stack_Extend_size( size, thread_config->is_fp );<br>
+  thread_config->stack_size = size;<br>
+  thread_config->stack_area = _Stack_Allocate( size );<br>
+}<br>
+<br>
 rtems_status_code rtems_task_create(<br>
   rtems_name           name,<br>
   rtems_task_priority  initial_priority,<br>
@@ -42,215 +65,18 @@ rtems_status_code rtems_task_create(<br>
   rtems_id            *id<br>
 )<br>
 {<br>
-  Thread_Control          *the_thread;<br>
-  Thread_Configuration     config;<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-  Objects_MP_Control      *the_global_object = NULL;<br>
-  bool                     is_global;<br>
-#endif<br>
-  bool                     status;<br>
-  rtems_attribute          the_attribute_set;<br>
-  bool                     valid;<br>
-  RTEMS_API_Control       *api;<br>
-  ASR_Information         *asr;<br>
-<br>
-  if ( !id )<br>
-   return RTEMS_INVALID_ADDRESS;<br>
-<br>
-  if ( !rtems_is_name_valid( name ) )<br>
-    return RTEMS_INVALID_NAME;<br>
-<br>
-  /*<br>
-   *  Core Thread Initialize insures we get the minimum amount of<br>
-   *  stack space.<br>
-   */<br>
-<br>
-  /*<br>
-   *  Fix the attribute set to match the attributes which<br>
-   *  this processor (1) requires and (2) is able to support.<br>
-   *  First add in the required flags for attribute_set<br>
-   *  Typically this might include FP if the platform<br>
-   *  or application required all tasks to be fp aware.<br>
-   *  Then turn off the requested bits which are not supported.<br>
-   */<br>
-<br>
-  the_attribute_set = _Attributes_Set( attribute_set, ATTRIBUTES_REQUIRED );<br>
-  the_attribute_set =<br>
-    _Attributes_Clear( the_attribute_set, ATTRIBUTES_NOT_SUPPORTED );<br>
+  rtems_task_config config;<br>
<br>
   memset( &config, 0, sizeof( config ) );<br>
-  config.budget_algorithm = _Modes_Is_timeslice( initial_modes ) ?<br>
-    THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE<br>
-      : THREAD_CPU_BUDGET_ALGORITHM_NONE,<br>
-  config.isr_level =  _Modes_Get_interrupt_level( initial_modes );<br>
-  config.name.name_u32 = name;<br>
-  config.is_fp = _Attributes_Is_floating_point( the_attribute_set );<br>
-  config.is_preemptible = _Modes_Is_preempt( initial_modes );<br>
-  config.stack_size = _Stack_Ensure_minimum( stack_size );<br>
-  config.stack_size = _Stack_Extend_size( config.stack_size, config.is_fp );<br>
-<br>
-  /*<br>
-   *  Validate the RTEMS API priority and convert it to the core priority range.<br>
-   */<br>
-<br>
-  if ( !_Attributes_Is_system_task( the_attribute_set ) ) {<br>
-    if ( initial_priority == PRIORITY_MINIMUM ) {<br>
-      return RTEMS_INVALID_PRIORITY;<br>
-    }<br>
-  }<br>
-<br>
-  config.scheduler = _Thread_Scheduler_get_home( _Thread_Get_executing() );<br>
-<br>
-  config.priority = _RTEMS_Priority_To_core(<br>
-    config.scheduler,<br>
-    initial_priority,<br>
-    &valid<br>
+  <a href="http://config.name" rel="noreferrer" target="_blank">config.name</a> = name;<br>
+  config.initial_priority = initial_priority;<br>
+  config.storage_size = stack_size;<br>
+  config.initial_modes = initial_modes;<br>
+  config.attributes = attribute_set;<br>
+<br>
+  return _RTEMS_tasks_Create(<br>
+    &config,<br>
+    id,<br>
+    _RTEMS_tasks_Allocate_and_prepare_stack<br>
   );<br>
-  if ( !valid ) {<br>
-    return RTEMS_INVALID_PRIORITY;<br>
-  }<br>
-<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-  if ( !_System_state_Is_multiprocessing ) {<br>
-    the_attribute_set = _Attributes_Clear( the_attribute_set, RTEMS_GLOBAL );<br>
-  }<br>
-<br>
-  is_global = _Attributes_Is_global( the_attribute_set );<br>
-#endif<br>
-<br>
-  /*<br>
-   *  Allocate the thread control block and -- if the task is global --<br>
-   *  allocate a global object control block.<br>
-   *<br>
-   *  NOTE:  This routine does not use the combined allocate and open<br>
-   *         global object routine (_Objects_MP_Allocate_and_open) because<br>
-   *         this results in a lack of control over when memory is allocated<br>
-   *         and can be freed in the event of an error.<br>
-   */<br>
-  the_thread = _RTEMS_tasks_Allocate();<br>
-<br>
-  if ( !the_thread ) {<br>
-    _Objects_Allocator_unlock();<br>
-    return RTEMS_TOO_MANY;<br>
-  }<br>
-<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-  if ( is_global ) {<br>
-    the_global_object = _Objects_MP_Allocate_global_object();<br>
-<br>
-    if ( _Objects_MP_Is_null_global_object( the_global_object ) ) {<br>
-      _RTEMS_tasks_Free( the_thread );<br>
-      _Objects_Allocator_unlock();<br>
-      return RTEMS_TOO_MANY;<br>
-    }<br>
-  }<br>
-#endif<br>
-<br>
-  config.stack_free = _Stack_Free;<br>
-  config.stack_area = _Stack_Allocate( config.stack_size );<br>
-  status = ( config.stack_area != NULL );<br>
-<br>
-  /*<br>
-   *  Initialize the core thread for this task.<br>
-   */<br>
-<br>
-  if ( status ) {<br>
-    status = _Thread_Initialize(<br>
-      &_RTEMS_tasks_Information,<br>
-      the_thread,<br>
-      &config<br>
-    );<br>
-  }<br>
-<br>
-  if ( !status ) {<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-    if ( is_global )<br>
-      _Objects_MP_Free_global_object( the_global_object );<br>
-#endif<br>
-    _RTEMS_tasks_Free( the_thread );<br>
-    _Objects_Allocator_unlock();<br>
-    return RTEMS_UNSATISFIED;<br>
-  }<br>
-<br>
-  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];<br>
-  asr = &api->Signal;<br>
-<br>
-  asr->is_enabled = _Modes_Is_asr_disabled(initial_modes) ? false : true;<br>
-<br>
-  *id = the_thread->Object.id;<br>
-<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-  the_thread->is_global = is_global;<br>
-  if ( is_global ) {<br>
-<br>
-    _Objects_MP_Open(<br>
-      &_RTEMS_tasks_Information.Objects,<br>
-      the_global_object,<br>
-      name,<br>
-      the_thread->Object.id<br>
-    );<br>
-<br>
-    _RTEMS_tasks_MP_Send_process_packet(<br>
-      RTEMS_TASKS_MP_ANNOUNCE_CREATE,<br>
-      the_thread->Object.id,<br>
-      name<br>
-    );<br>
-<br>
-   }<br>
-#endif<br>
-<br>
-  _Objects_Allocator_unlock();<br>
-  return RTEMS_SUCCESSFUL;<br>
-}<br>
-<br>
-static void _RTEMS_tasks_Start_extension(<br>
-  Thread_Control *executing,<br>
-  Thread_Control *started<br>
-)<br>
-{<br>
-  RTEMS_API_Control *api;<br>
-<br>
-  api = started->API_Extensions[ THREAD_API_RTEMS ];<br>
-<br>
-  _Event_Initialize( &api->Event );<br>
-  _Event_Initialize( &api->System_event );<br>
-}<br>
-<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-static void _RTEMS_tasks_Terminate_extension( Thread_Control *executing )<br>
-{<br>
-  if ( executing->is_global ) {<br>
-    _Objects_MP_Close(<br>
-      &_RTEMS_tasks_Information.Objects,<br>
-      executing->Object.id<br>
-    );<br>
-    _RTEMS_tasks_MP_Send_process_packet(<br>
-      RTEMS_TASKS_MP_ANNOUNCE_DELETE,<br>
-      executing->Object.id,<br>
-      0                                /* Not used */<br>
-    );<br>
-  }<br>
 }<br>
-#endif<br>
-<br>
-static User_extensions_Control _RTEMS_tasks_User_extensions = {<br>
-  .Callouts = {<br>
-#if defined(RTEMS_MULTIPROCESSING)<br>
-    .thread_terminate = _RTEMS_tasks_Terminate_extension,<br>
-#endif<br>
-    .thread_start     = _RTEMS_tasks_Start_extension,<br>
-    .thread_restart   = _RTEMS_tasks_Start_extension<br>
-  }<br>
-};<br>
-<br>
-static void _RTEMS_tasks_Manager_initialization( void )<br>
-{<br>
-  _Thread_Initialize_information( &_RTEMS_tasks_Information );<br>
-  _User_extensions_Add_API_set( &_RTEMS_tasks_User_extensions );<br>
-}<br>
-<br>
-RTEMS_SYSINIT_ITEM(<br>
-  _RTEMS_tasks_Manager_initialization,<br>
-  RTEMS_SYSINIT_CLASSIC_TASKS,<br>
-  RTEMS_SYSINIT_ORDER_MIDDLE<br>
-);<br></blockquote><div><br></div><div>Is all of this just turning rtems_task_create into a wrapper for the task create from config?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
diff --git a/cpukit/rtems/src/taskcreatefromconfig.c b/cpukit/rtems/src/taskcreatefromconfig.c<br>
new file mode 100644<br>
index 0000000000..952d3a3a3c<br>
--- /dev/null<br>
+++ b/cpukit/rtems/src/taskcreatefromconfig.c<br>
@@ -0,0 +1,274 @@<br>
+/**<br>
+ * @file<br>
+ *<br>
+ * @ingroup ClassicTasks<br>
+ *<br>
+ * @brief RTEMS Task Create from Config<br>
+ */<br>
+<br>
+/*<br>
+ *  COPYRIGHT (c) 1989-2014,2016.<br>
+ *  On-Line Applications Research Corporation (OAR).<br>
+ *<br>
+ *  The license and distribution terms for this file may be<br>
+ *  found in the file LICENSE in this distribution or at<br>
+ *  <a href="http://www.rtems.org/license/LICENSE" rel="noreferrer" target="_blank">http://www.rtems.org/license/LICENSE</a>.<br>
+ */<br>
+<br>
+#ifdef HAVE_CONFIG_H<br>
+#include "config.h"<br>
+#endif<br>
+<br>
+#include <rtems/rtems/tasksimpl.h><br>
+#include <rtems/rtems/attrimpl.h><br>
+#include <rtems/rtems/eventimpl.h><br>
+#include <rtems/rtems/modesimpl.h><br>
+#include <rtems/rtems/support.h><br>
+#include <rtems/score/apimutex.h><br>
+#include <rtems/score/schedulerimpl.h><br>
+#include <rtems/score/stackimpl.h><br>
+#include <rtems/score/sysstate.h><br>
+#include <rtems/score/threadimpl.h><br>
+#include <rtems/score/userextimpl.h><br>
+#include <rtems/sysinit.h><br>
+<br>
+#include <string.h><br>
+<br>
+static void _RTEMS_tasks_Prepare_user_stack(<br>
+  Thread_Configuration    *thread_config,<br>
+  const rtems_task_config *config<br>
+)<br>
+{<br>
+  thread_config->stack_size = config->storage_size;<br>
+  thread_config->stack_area = config->storage_area;<br>
+<br>
+  if ( config->storage_free != NULL ) {<br>
+    thread_config->stack_free = config->storage_free;<br>
+  } else {<br>
+    thread_config->stack_free = _Stack_Free_nothing;<br>
+  }<br>
+}<br>
+<br>
+rtems_status_code rtems_task_create_from_config(<br>
+  const rtems_task_config *config,<br>
+  rtems_id                *id<br>
+)<br>
+{<br>
+  return _RTEMS_tasks_Create( config, id, _RTEMS_tasks_Prepare_user_stack );<br>
+}<br>
+<br>
+rtems_status_code _RTEMS_tasks_Create(<br>
+  const rtems_task_config   *config,<br>
+  rtems_id                  *id,<br>
+  RTEMS_tasks_Prepare_stack  prepare_stack<br>
+)<br>
+{<br>
+  Thread_Control          *the_thread;<br>
+  Thread_Configuration     thread_config;<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+  Objects_MP_Control      *the_global_object = NULL;<br>
+  bool                     is_global;<br>
+#endif<br>
+  bool                     status;<br>
+  rtems_attribute          attributes;<br>
+  bool                     valid;<br>
+  RTEMS_API_Control       *api;<br>
+  ASR_Information         *asr;<br>
+<br>
+  if ( !id )<br>
+   return RTEMS_INVALID_ADDRESS;<br>
+<br>
+  if ( !rtems_is_name_valid( config->name ) )<br>
+    return RTEMS_INVALID_NAME;<br>
+<br>
+  /*<br>
+   *  Core Thread Initialize insures we get the minimum amount of<br>
+   *  stack space.<br>
+   */<br>
+<br>
+  /*<br>
+   *  Fix the attribute set to match the attributes which<br>
+   *  this processor (1) requires and (2) is able to support.<br>
+   *  First add in the required flags for attributes<br>
+   *  Typically this might include FP if the platform<br>
+   *  or application required all tasks to be fp aware.<br>
+   *  Then turn off the requested bits which are not supported.<br>
+   */<br>
+<br>
+  attributes = _Attributes_Set( config->attributes, ATTRIBUTES_REQUIRED );<br>
+  attributes = _Attributes_Clear( attributes, ATTRIBUTES_NOT_SUPPORTED );<br>
+<br>
+  memset( &thread_config, 0, sizeof( thread_config ) );<br>
+  thread_config.budget_algorithm = _Modes_Is_timeslice( config->initial_modes ) ?<br>
+    THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE<br>
+      : THREAD_CPU_BUDGET_ALGORITHM_NONE,<br>
+  thread_config.isr_level =  _Modes_Get_interrupt_level( config->initial_modes );<br>
+  thread_config.name.name_u32 = config->name;<br>
+  thread_config.is_fp = _Attributes_Is_floating_point( attributes );<br>
+  thread_config.is_preemptible = _Modes_Is_preempt( config->initial_modes );<br>
+<br>
+  /*<br>
+   *  Validate the RTEMS API priority and convert it to the core priority range.<br>
+   */<br>
+<br>
+  if ( !_Attributes_Is_system_task( attributes ) ) {<br>
+    if ( config->initial_priority == PRIORITY_MINIMUM ) {<br>
+      return RTEMS_INVALID_PRIORITY;<br>
+    }<br>
+  }<br>
+<br>
+  thread_config.scheduler =<br>
+    _Thread_Scheduler_get_home( _Thread_Get_executing() );<br>
+<br>
+  thread_config.priority = _RTEMS_Priority_To_core(<br>
+    thread_config.scheduler,<br>
+    config->initial_priority,<br>
+    &valid<br>
+  );<br>
+  if ( !valid ) {<br>
+    return RTEMS_INVALID_PRIORITY;<br>
+  }<br>
+<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+  if ( !_System_state_Is_multiprocessing ) {<br>
+    attributes = _Attributes_Clear( attributes, RTEMS_GLOBAL );<br>
+  }<br>
+<br>
+  is_global = _Attributes_Is_global( attributes );<br>
+#endif<br>
+<br>
+  /*<br>
+   *  Allocate the thread control block and -- if the task is global --<br>
+   *  allocate a global object control block.<br>
+   *<br>
+   *  NOTE:  This routine does not use the combined allocate and open<br>
+   *         global object routine (_Objects_MP_Allocate_and_open) because<br>
+   *         this results in a lack of control over when memory is allocated<br>
+   *         and can be freed in the event of an error.<br>
+   */<br>
+  the_thread = _RTEMS_tasks_Allocate();<br>
+<br>
+  if ( !the_thread ) {<br>
+    _Objects_Allocator_unlock();<br>
+    return RTEMS_TOO_MANY;<br>
+  }<br>
+<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+  if ( is_global ) {<br>
+    the_global_object = _Objects_MP_Allocate_global_object();<br>
+<br>
+    if ( _Objects_MP_Is_null_global_object( the_global_object ) ) {<br>
+      _RTEMS_tasks_Free( the_thread );<br>
+      _Objects_Allocator_unlock();<br>
+      return RTEMS_TOO_MANY;<br>
+    }<br>
+  }<br>
+#endif<br>
+<br>
+  ( *prepare_stack )( &thread_config, config );<br>
+  status = ( thread_config.stack_area != NULL );<br>
+<br>
+  /*<br>
+   *  Initialize the core thread for this task.<br>
+   */<br>
+<br>
+  if ( status ) {<br>
+    status = _Thread_Initialize(<br>
+      &_RTEMS_tasks_Information,<br>
+      the_thread,<br>
+      &thread_config<br>
+    );<br>
+  }<br>
+<br>
+  if ( !status ) {<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+    if ( is_global )<br>
+      _Objects_MP_Free_global_object( the_global_object );<br>
+#endif<br>
+    _RTEMS_tasks_Free( the_thread );<br>
+    _Objects_Allocator_unlock();<br>
+    return RTEMS_UNSATISFIED;<br>
+  }<br>
+<br>
+  api = the_thread->API_Extensions[ THREAD_API_RTEMS ];<br>
+  asr = &api->Signal;<br>
+<br>
+  asr->is_enabled = !_Modes_Is_asr_disabled( config->initial_modes );<br>
+<br>
+  *id = the_thread->Object.id;<br>
+<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+  the_thread->is_global = is_global;<br>
+  if ( is_global ) {<br>
+<br>
+    _Objects_MP_Open(<br>
+      &_RTEMS_tasks_Information.Objects,<br>
+      the_global_object,<br>
+      config->name,<br>
+      the_thread->Object.id<br>
+    );<br>
+<br>
+    _RTEMS_tasks_MP_Send_process_packet(<br>
+      RTEMS_TASKS_MP_ANNOUNCE_CREATE,<br>
+      the_thread->Object.id,<br>
+      config->name<br>
+    );<br>
+<br>
+   }<br>
+#endif<br>
+<br>
+  _Objects_Allocator_unlock();<br>
+  return RTEMS_SUCCESSFUL;<br>
+}<br>
+<br>
+static void _RTEMS_tasks_Start_extension(<br>
+  Thread_Control *executing,<br>
+  Thread_Control *started<br>
+)<br>
+{<br>
+  RTEMS_API_Control *api;<br>
+<br>
+  api = started->API_Extensions[ THREAD_API_RTEMS ];<br>
+<br>
+  _Event_Initialize( &api->Event );<br>
+  _Event_Initialize( &api->System_event );<br>
+}<br>
+<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+static void _RTEMS_tasks_Terminate_extension( Thread_Control *executing )<br>
+{<br>
+  if ( executing->is_global ) {<br>
+    _Objects_MP_Close(<br>
+      &_RTEMS_tasks_Information.Objects,<br>
+      executing->Object.id<br>
+    );<br>
+    _RTEMS_tasks_MP_Send_process_packet(<br>
+      RTEMS_TASKS_MP_ANNOUNCE_DELETE,<br>
+      executing->Object.id,<br>
+      0                                /* Not used */<br>
+    );<br>
+  }<br>
+}<br>
+#endif<br>
+<br>
+static User_extensions_Control _RTEMS_tasks_User_extensions = {<br>
+  .Callouts = {<br>
+#if defined(RTEMS_MULTIPROCESSING)<br>
+    .thread_terminate = _RTEMS_tasks_Terminate_extension,<br>
+#endif<br>
+    .thread_start     = _RTEMS_tasks_Start_extension,<br>
+    .thread_restart   = _RTEMS_tasks_Start_extension<br>
+  }<br>
+};<br>
+<br>
+static void _RTEMS_tasks_Manager_initialization( void )<br>
+{<br>
+  _Thread_Initialize_information( &_RTEMS_tasks_Information );<br>
+  _User_extensions_Add_API_set( &_RTEMS_tasks_User_extensions );<br>
+}<br>
+<br>
+RTEMS_SYSINIT_ITEM(<br>
+  _RTEMS_tasks_Manager_initialization,<br>
+  RTEMS_SYSINIT_CLASSIC_TASKS,<br>
+  RTEMS_SYSINIT_ORDER_MIDDLE<br>
+);<br>
diff --git a/testsuites/sptests/sp01/init.c b/testsuites/sptests/sp01/init.c<br>
index 2719c84fc8..a0a332987d 100644<br>
--- a/testsuites/sptests/sp01/init.c<br>
+++ b/testsuites/sptests/sp01/init.c<br>
@@ -16,6 +16,19 @@<br>
<br>
 const char rtems_test_name[] = "SP 1";<br>
<br>
+RTEMS_TASK_STORAGE_ALIGNMENT static char Task_1_storage[<br>
+  RTEMS_TASK_STORAGE_SIZE( 2 * RTEMS_MINIMUM_STACK_SIZE, RTEMS_FLOATING_POINT )<br></blockquote><div><br></div><div>This line appears to be too long.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+];<br>
+<br>
+static const rtems_task_config Task_1_config = {<br>
+  .name = rtems_build_name( 'T', 'A', '1', ' ' ),<br>
+  .initial_priority = 1,<br>
+  .storage_area = Task_1_storage,<br>
+  .storage_size = sizeof( Task_1_storage ),<br>
+  .initial_modes = RTEMS_DEFAULT_MODES,<br>
+  .attributes = RTEMS_FLOATING_POINT<br>
+};<br>
+<br>
 rtems_task Init(<br>
   rtems_task_argument argument<br>
 )<br>
@@ -30,15 +43,8 @@ rtems_task Init(<br>
   status = rtems_clock_set( &time );<br>
   directive_failed( status, "rtems_clock_set" );<br>
<br>
-  status = rtems_task_create(<br>
-    rtems_build_name( 'T', 'A', '1', ' ' ),<br>
-    1,<br>
-    RTEMS_MINIMUM_STACK_SIZE * 2,<br>
-    RTEMS_DEFAULT_MODES,<br>
-    RTEMS_DEFAULT_ATTRIBUTES,<br>
-    &id<br>
-  );<br>
-  directive_failed( status, "rtems_task_create of TA1" );<br>
+  status = rtems_task_create_from_config( &Task_1_config, &id );<br>
+  directive_failed( status, "rtems_task_create_from_config of TA1" );<br>
<br>
   status = rtems_task_start( id, Task_1_through_3, 1 );<br>
   directive_failed( status, "rtems_task_start of TA1" );<br>
diff --git a/testsuites/sptests/sp01/sp01.doc b/testsuites/sptests/sp01/sp01.doc<br>
index d7d9f5d902..62bbe956d3 100644<br>
--- a/testsuites/sptests/sp01/sp01.doc<br>
+++ b/testsuites/sptests/sp01/sp01.doc<br>
@@ -9,6 +9,7 @@<br>
 test name:  sp01<br>
<br>
 directives:<br>
+  rtems_task_build<br>
   rtems_task_create<br>
   rtems_task_start<br>
   rtems_task_wake_after<br>
diff --git a/testsuites/sptests/sp01/system.h b/testsuites/sptests/sp01/system.h<br>
index bde5328aa9..e2047b4d3a 100644<br>
--- a/testsuites/sptests/sp01/system.h<br>
+++ b/testsuites/sptests/sp01/system.h<br>
@@ -28,7 +28,7 @@ rtems_task Task_1_through_3(<br>
<br>
 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE<br>
<br>
-#define CONFIGURE_EXTRA_TASK_STACKS         (4 * RTEMS_MINIMUM_STACK_SIZE)<br>
+#define CONFIGURE_EXTRA_TASK_STACKS         (2 * RTEMS_MINIMUM_STACK_SIZE)<br>
 #define CONFIGURE_MAXIMUM_TASKS             4<br></blockquote><div><br></div><div>This seems to be missing lowering the computation for number of</div><div>minimum stacks reserved</div><div><br></div><div>--joel</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
 #include <rtems/confdefs.h><br>
-- <br>
2.26.2<br>
<br>
_______________________________________________<br>
devel mailing list<br>
<a href="mailto:devel@rtems.org" target="_blank">devel@rtems.org</a><br>
<a href="http://lists.rtems.org/mailman/listinfo/devel" rel="noreferrer" target="_blank">http://lists.rtems.org/mailman/listinfo/devel</a><br>
</blockquote></div></div>