<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>