From 6942e5f99171d1cb38c2c573aba8cb9212d7efd8 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 9 Apr 2020 12:12:13 +0200 Subject: rtems: Add rtems_task_construct() In contrast to rtems_task_create() this function constructs a task with a user-provided task storage area. The new directive uses a configuration structure instead of individual parameters. Add RTEMS_TASK_STORAGE_SIZE() to calculate the recommended size of a task storage area based on the task attributes and the size dedicated to the task stack and thread-local storage. This macro may allow future extensions without breaking the API. Add application configuration option CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE to adjust RTEMS Workspace size estimate. Update #3959. --- cpukit/doxygen/appl-config.h | 22 +++ cpukit/include/rtems/confdefs/threads.h | 8 + cpukit/include/rtems/confdefs/wkspace.h | 4 +- cpukit/include/rtems/rtems/tasks.h | 184 ++++++++++++++++++++ cpukit/include/rtems/rtems/tasksimpl.h | 11 ++ cpukit/rtems/src/taskconstruct.c | 300 ++++++++++++++++++++++++++++++++ cpukit/rtems/src/taskcreate.c | 282 ++++++------------------------ spec/build/cpukit/librtemscpu.yml | 1 + testsuites/sptests/sp01/init.c | 24 ++- testsuites/sptests/sp01/sp01.doc | 1 + testsuites/sptests/sp01/system.h | 3 +- 11 files changed, 604 insertions(+), 236 deletions(-) create mode 100644 cpukit/rtems/src/taskconstruct.c diff --git a/cpukit/doxygen/appl-config.h b/cpukit/doxygen/appl-config.h index 47a8e2d39e..0386f83315 100644 --- a/cpukit/doxygen/appl-config.h +++ b/cpukit/doxygen/appl-config.h @@ -901,6 +901,28 @@ */ #define CONFIGURE_MAXIMUM_USER_EXTENSIONS +/** + * @brief This configuration option is an integer define. + * + * The value of this configuration option defines the minimum count of Classic + * API Tasks which are constructed by rtems_task_construct(). + * + * @par Default Value + * The default value is 0. + * + * @par Value Constraints + * The value of this configuration option shall be greater than or equal to 0 + * and less than or equal to #CONFIGURE_MAXIMUM_TASKS. + * + * @par Notes + * By default, the calculation for the required memory in the RTEMS Workspace + * for tasks assumes that all Classic API Tasks are created by + * rtems_task_create(). This configuration option can be used to reduce the + * required memory for the system-provided task storage areas since tasks + * constructed by rtems_task_construct() use a user-provided task storage area. + */ +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE + /** @} */ /** diff --git a/cpukit/include/rtems/confdefs/threads.h b/cpukit/include/rtems/confdefs/threads.h index 9e34696e61..8f72407695 100644 --- a/cpukit/include/rtems/confdefs/threads.h +++ b/cpukit/include/rtems/confdefs/threads.h @@ -60,6 +60,14 @@ #define _CONFIGURE_TASKS ( CONFIGURE_MAXIMUM_TASKS + _CONFIGURE_LIBBLOCK_TASKS ) +#ifndef CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE + #define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE 0 +#endif + +#if CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE > CONFIGURE_MAXIMUM_TASKS + #error "CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE shall be less than or equal to CONFIGURE_MAXIMUM_TASKS" +#endif + #ifndef CONFIGURE_MAXIMUM_POSIX_THREADS #define CONFIGURE_MAXIMUM_POSIX_THREADS 0 #endif diff --git a/cpukit/include/rtems/confdefs/wkspace.h b/cpukit/include/rtems/confdefs/wkspace.h index de476dbf82..3b464899dc 100644 --- a/cpukit/include/rtems/confdefs/wkspace.h +++ b/cpukit/include/rtems/confdefs/wkspace.h @@ -100,7 +100,9 @@ + _CONFIGURE_POSIX_INIT_THREAD_STACK_EXTRA \ + _CONFIGURE_LIBBLOCK_TASKS_STACK_EXTRA \ + CONFIGURE_EXTRA_TASK_STACKS \ - + rtems_resource_maximum_per_allocation( _CONFIGURE_TASKS ) \ + + rtems_resource_maximum_per_allocation( \ + _CONFIGURE_TASKS - CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE \ + ) \ * _Configure_From_stackspace( CONFIGURE_MINIMUM_TASK_STACK_SIZE ) \ + rtems_resource_maximum_per_allocation( CONFIGURE_MAXIMUM_POSIX_THREADS ) \ * _Configure_From_stackspace( CONFIGURE_MINIMUM_POSIX_THREAD_STACK_SIZE ) \ diff --git a/cpukit/include/rtems/rtems/tasks.h b/cpukit/include/rtems/rtems/tasks.h index e07db6cd2b..d05a46ff42 100644 --- a/cpukit/include/rtems/rtems/tasks.h +++ b/cpukit/include/rtems/rtems/tasks.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -173,6 +174,189 @@ rtems_status_code rtems_task_create( */ #define RTEMS_TASK_STORAGE_ALIGNMENT CPU_HEAP_ALIGNMENT +/** + * @brief Returns the recommended task storage area size for the specified size + * and task attributes. + * + * @param _size is the size dedicated to the task stack and thread-local + * storage in bytes. + * + * @param _attributes is the attribute set of the task using the storage area. + * + * @return The recommended task storage area size calculated from the input + * parameters is returned. + */ +#if CPU_ALL_TASKS_ARE_FP == TRUE + #define RTEMS_TASK_STORAGE_SIZE( _size, _attributes ) \ + ( ( _size ) + CONTEXT_FP_SIZE ) +#else + #define RTEMS_TASK_STORAGE_SIZE( _size, _attributes ) \ + ( ( _size ) + \ + ( ( ( _attributes ) & RTEMS_FLOATING_POINT ) != 0 ? \ + CONTEXT_FP_SIZE : 0 ) ) +#endif + +/** + * @brief This structure defines the configuration of a task constructed by + * rtems_task_construct(). + */ +typedef struct { + /** + * @brief This member defines the name of the task. + */ + rtems_name name; + + /** + * @brief This member defines the initial priority of the task. + */ + rtems_task_priority initial_priority; + + /** + * @brief This member shall point to the task storage area begin. + * + * The task storage area will contain the task stack, the thread-local storage, + * and the floating-point context on architectures with a separate + * floating-point context. + * + * The task storage area begin address and size should be aligned by + * #RTEMS_TASK_STORAGE_ALIGNMENT. To avoid memory waste, use RTEMS_ALIGNED() + * and #RTEMS_TASK_STORAGE_ALIGNMENT to enforce the recommended alignment of a + * statically allocated task storage area. + */ + void *storage_area; + + /** + * @brief This member defines size of the task storage area in bytes. + * + * Use the RTEMS_TASK_STORAGE_SIZE() macro to determine the recommended task + * storage area size. + */ + size_t storage_size; + + /** + * @brief This member defines the maximum thread-local storage size supported + * by the task storage area. + * + * Use RTEMS_ALIGN_UP() and #RTEMS_TASK_STORAGE_ALIGNMENT to adjust the size to + * meet the minimum alignment requirement of a thread-local storage area used + * to construct a task. + * + * If the value is less than the actual thread-local storage size, then the + * task construction by rtems_task_construct() fails. + * + * If the is less than the task storage area size, then the task construction + * by rtems_task_construct() fails. + * + * The actual thread-local storage size is determined when the application + * executable is linked. The ``rtems-exeinfo`` command line tool included in + * the RTEMS Tools can be used to obtain the thread-local storage size and + * alignment of an application executable. + * + * The application may configure the maximum thread-local storage size for all + * threads explicitly through the #CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE + * configuration option. + */ + size_t maximum_thread_local_storage_size; + + /** + * @brief This member defines the optional handler to free the task storage + * area. + * + * It is called on exactly two mutually exclusive occasions. Firstly, when the + * task construction aborts due to a failed task create extension, or secondly, + * when the task is deleted. It is called from task context under protection + * of the object allocator lock. It is allowed to call free() in this handler. + * If handler is NULL, then no action will be performed. + */ + void ( *storage_free )( void * ); + + /** + * @brief This member defines the initial modes of the task. + */ + rtems_mode initial_modes; + + /** + * @brief This member defines the attributes of the task. + */ + rtems_attribute attributes; +} rtems_task_config; + +/** + * @brief Constructs a task from the specified the task configuration. + * + * In contrast to tasks created by rtems_task_create(), the tasks constructed + * by this directive use a user-provided task storage area. 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. + * + * This directive is intended for applications which do not want to use the + * RTEMS Workspace and instead statically allocate all operating system + * resources. It is not recommended to use rtems_task_create() and + * rtems_task_construct() together in an application. It is also not + * recommended to use rtems_task_construct() for drivers or general purpose + * libraries. The reason for these recommendations is that the task + * configuration needs settings which can be only given with a through + * knowledge of the application resources. + * + * An application based solely on static allocation can avoid any runtime + * memory allocators. This can simplfiy the application architecture as well + * as any analysis that may be required. + * + * The stack space estimate done by assumes that all tasks + * are created by rtems_task_create(). The estimate can be adjusted to take + * user-provided task storage areas into account through the + * #CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE application + * configuration option. + * + * The #CONFIGURE_MAXIMUM_TASKS should include tasks constructed by + * rtems_task_construct(). + * + * @param config is the task configuration. + * + * @param[out] id is the pointer to an object identifier variable. The + * identifier of the constructed task object will be stored in this variable, + * in case of a successful operation. + * + * @retval ::RTEMS_SUCCESSFUL The requested operation was successful. + * + * @retval ::RTEMS_INVALID_ADDRESS The id parameter was NULL. + * + * @retval ::RTEMS_INVALID_NAME The task name was invalid. + * + * @retval ::RTEMS_INVALID_PRIORITY The initial task priority was invalid. + * + * @retval ::RTEMS_INVALID_SIZE The thread-local storage size is greater than + * the maximum thread-local storage size specified in the task configuration. + * The thread-local storage size is determined by the thread-local variables + * used by the application and #CONFIGURE_MAXIMUM_THREAD_LOCAL_STORAGE_SIZE. + * + * @retval ::RTEMS_INVALID_SIZE The task storage area was too small to provide + * a task stack of the configured minimum size, see + * #CONFIGURE_MINIMUM_TASK_STACK_SIZE. 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. + * + * @retval ::RTEMS_TOO_MANY There was no inactive task object available to + * construct a task. + * + * @retval ::RTEMS_TOO_MANY In multiprocessing configurations, there was no + * inactive global object available to construct a global task. + * + * @retval ::RTEMS_UNSATISFIED One of the task create extensions failed during + * the task construction. + * + * @retval ::RTEMS_UNSATISFIED In SMP configurations, the non-preemption mode + * was not supported. + * + * @retval ::RTEMS_UNSATISFIED In SMP configurations, the interrupt level mode + * was not supported. + */ +rtems_status_code rtems_task_construct( + const rtems_task_config *config, + rtems_id *id +); + /** * @brief RTEMS Task Name to Id * diff --git a/cpukit/include/rtems/rtems/tasksimpl.h b/cpukit/include/rtems/rtems/tasksimpl.h index c9544f8c27..a0aa252cea 100644 --- a/cpukit/include/rtems/rtems/tasksimpl.h +++ b/cpukit/include/rtems/rtems/tasksimpl.h @@ -42,6 +42,17 @@ extern "C" { */ void _RTEMS_tasks_Initialize_user_tasks( void ); +typedef rtems_status_code ( *RTEMS_tasks_Prepare_stack )( + Thread_Configuration *, + const rtems_task_config * +); + +rtems_status_code _RTEMS_tasks_Create( + const rtems_task_config *config, + rtems_id *id, + RTEMS_tasks_Prepare_stack prepare_stack +); + RTEMS_INLINE_ROUTINE Thread_Control *_RTEMS_tasks_Allocate(void) { _Objects_Allocator_lock(); diff --git a/cpukit/rtems/src/taskconstruct.c b/cpukit/rtems/src/taskconstruct.c new file mode 100644 index 0000000000..76ef8ce5d6 --- /dev/null +++ b/cpukit/rtems/src/taskconstruct.c @@ -0,0 +1,300 @@ +/** + * @file + * + * @ingroup ClassicTasks + * + * @brief RTEMS Task Create from Config + */ + +/* + * COPYRIGHT (c) 1989-2014,2016. + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static rtems_status_code _RTEMS_tasks_Prepare_user_stack( + Thread_Configuration *thread_config, + const rtems_task_config *config +) +{ + size_t size; + + size = _TLS_Get_allocation_size(); + + if ( config->maximum_thread_local_storage_size < size ) { + return RTEMS_INVALID_SIZE; + } + +#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE ) + if ( thread_config->is_fp ) { + size += CONTEXT_FP_SIZE; + } +#endif + + size += _Stack_Minimum(); + + if ( config->storage_size < size ) { + return RTEMS_INVALID_SIZE; + } + + thread_config->stack_size = config->storage_size; + thread_config->stack_area = config->storage_area; + + if ( config->storage_free != NULL ) { + thread_config->stack_free = config->storage_free; + } else { + thread_config->stack_free = _Stack_Free_nothing; + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code rtems_task_construct( + const rtems_task_config *config, + rtems_id *id +) +{ + return _RTEMS_tasks_Create( config, id, _RTEMS_tasks_Prepare_user_stack ); +} + +rtems_status_code _RTEMS_tasks_Create( + const rtems_task_config *config, + rtems_id *id, + RTEMS_tasks_Prepare_stack prepare_stack +) +{ + Thread_Control *the_thread; + Thread_Configuration thread_config; +#if defined(RTEMS_MULTIPROCESSING) + Objects_MP_Control *the_global_object = NULL; + bool is_global; +#endif + rtems_status_code status; + rtems_attribute attributes; + bool valid; + RTEMS_API_Control *api; + ASR_Information *asr; + + if ( !id ) + return RTEMS_INVALID_ADDRESS; + + if ( !rtems_is_name_valid( config->name ) ) + return RTEMS_INVALID_NAME; + + /* + * Core Thread Initialize insures we get the minimum amount of + * stack space. + */ + + /* + * Fix the attribute set to match the attributes which + * this processor (1) requires and (2) is able to support. + * First add in the required flags for attributes + * Typically this might include FP if the platform + * or application required all tasks to be fp aware. + * Then turn off the requested bits which are not supported. + */ + + attributes = _Attributes_Set( config->attributes, ATTRIBUTES_REQUIRED ); + attributes = _Attributes_Clear( attributes, ATTRIBUTES_NOT_SUPPORTED ); + + memset( &thread_config, 0, sizeof( thread_config ) ); + thread_config.budget_algorithm = _Modes_Is_timeslice( config->initial_modes ) ? + THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE + : THREAD_CPU_BUDGET_ALGORITHM_NONE, + thread_config.isr_level = _Modes_Get_interrupt_level( config->initial_modes ); + thread_config.name.name_u32 = config->name; + thread_config.is_fp = _Attributes_Is_floating_point( attributes ); + thread_config.is_preemptible = _Modes_Is_preempt( config->initial_modes ); + + /* + * Validate the RTEMS API priority and convert it to the core priority range. + */ + + if ( !_Attributes_Is_system_task( attributes ) ) { + if ( config->initial_priority == PRIORITY_MINIMUM ) { + return RTEMS_INVALID_PRIORITY; + } + } + + thread_config.scheduler = + _Thread_Scheduler_get_home( _Thread_Get_executing() ); + + thread_config.priority = _RTEMS_Priority_To_core( + thread_config.scheduler, + config->initial_priority, + &valid + ); + if ( !valid ) { + return RTEMS_INVALID_PRIORITY; + } + +#if defined(RTEMS_MULTIPROCESSING) + if ( !_System_state_Is_multiprocessing ) { + attributes = _Attributes_Clear( attributes, RTEMS_GLOBAL ); + } + + is_global = _Attributes_Is_global( attributes ); +#endif + + /* + * Allocate the thread control block and -- if the task is global -- + * allocate a global object control block. + * + * NOTE: This routine does not use the combined allocate and open + * global object routine (_Objects_MP_Allocate_and_open) because + * this results in a lack of control over when memory is allocated + * and can be freed in the event of an error. + */ + the_thread = _RTEMS_tasks_Allocate(); + + if ( !the_thread ) { + _Objects_Allocator_unlock(); + return RTEMS_TOO_MANY; + } + +#if defined(RTEMS_MULTIPROCESSING) + if ( is_global ) { + the_global_object = _Objects_MP_Allocate_global_object(); + + if ( _Objects_MP_Is_null_global_object( the_global_object ) ) { + _RTEMS_tasks_Free( the_thread ); + _Objects_Allocator_unlock(); + return RTEMS_TOO_MANY; + } + } +#endif + + status = ( *prepare_stack )( &thread_config, config ); + + /* + * Initialize the core thread for this task. + */ + + if ( status == RTEMS_SUCCESSFUL ) { + bool ok; + + ok = _Thread_Initialize( + &_RTEMS_tasks_Information, + the_thread, + &thread_config + ); + + if ( !ok ) { + status = RTEMS_UNSATISFIED; + } + } + + if ( status != RTEMS_SUCCESSFUL ) { +#if defined(RTEMS_MULTIPROCESSING) + if ( is_global ) + _Objects_MP_Free_global_object( the_global_object ); +#endif + _RTEMS_tasks_Free( the_thread ); + _Objects_Allocator_unlock(); + return status; + } + + api = the_thread->API_Extensions[ THREAD_API_RTEMS ]; + asr = &api->Signal; + + asr->is_enabled = !_Modes_Is_asr_disabled( config->initial_modes ); + + *id = the_thread->Object.id; + +#if defined(RTEMS_MULTIPROCESSING) + the_thread->is_global = is_global; + if ( is_global ) { + + _Objects_MP_Open( + &_RTEMS_tasks_Information.Objects, + the_global_object, + config->name, + the_thread->Object.id + ); + + _RTEMS_tasks_MP_Send_process_packet( + RTEMS_TASKS_MP_ANNOUNCE_CREATE, + the_thread->Object.id, + config->name + ); + + } +#endif + + _Objects_Allocator_unlock(); + return RTEMS_SUCCESSFUL; +} + +static void _RTEMS_tasks_Start_extension( + Thread_Control *executing, + Thread_Control *started +) +{ + RTEMS_API_Control *api; + + api = started->API_Extensions[ THREAD_API_RTEMS ]; + + _Event_Initialize( &api->Event ); + _Event_Initialize( &api->System_event ); +} + +#if defined(RTEMS_MULTIPROCESSING) +static void _RTEMS_tasks_Terminate_extension( Thread_Control *executing ) +{ + if ( executing->is_global ) { + _Objects_MP_Close( + &_RTEMS_tasks_Information.Objects, + executing->Object.id + ); + _RTEMS_tasks_MP_Send_process_packet( + RTEMS_TASKS_MP_ANNOUNCE_DELETE, + executing->Object.id, + 0 /* Not used */ + ); + } +} +#endif + +static User_extensions_Control _RTEMS_tasks_User_extensions = { + .Callouts = { +#if defined(RTEMS_MULTIPROCESSING) + .thread_terminate = _RTEMS_tasks_Terminate_extension, +#endif + .thread_start = _RTEMS_tasks_Start_extension, + .thread_restart = _RTEMS_tasks_Start_extension + } +}; + +static void _RTEMS_tasks_Manager_initialization( void ) +{ + _Thread_Initialize_information( &_RTEMS_tasks_Information ); + _User_extensions_Add_API_set( &_RTEMS_tasks_User_extensions ); +} + +RTEMS_SYSINIT_ITEM( + _RTEMS_tasks_Manager_initialization, + RTEMS_SYSINIT_CLASSIC_TASKS, + RTEMS_SYSINIT_ORDER_MIDDLE +); diff --git a/cpukit/rtems/src/taskcreate.c b/cpukit/rtems/src/taskcreate.c index 5486ac9b6e..917d931424 100644 --- a/cpukit/rtems/src/taskcreate.c +++ b/cpukit/rtems/src/taskcreate.c @@ -1,17 +1,36 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + /** - * @file + * @file + * + * @ingroup ClassicTasks * - * @brief RTEMS Task Create - * @ingroup ClassicTasks + * @brief RTEMS Task Create */ /* - * COPYRIGHT (c) 1989-2014,2016. - * On-Line Applications Research Corporation (OAR). + * Copyright (C) 2020 embedded brains GmbH (http://www.embedded-brains.de) + * + * 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. * - * 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 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 @@ -19,238 +38,51 @@ #endif #include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -rtems_status_code rtems_task_create( - rtems_name name, - rtems_task_priority initial_priority, - size_t stack_size, - rtems_mode initial_modes, - rtems_attribute attribute_set, - rtems_id *id +static rtems_status_code _RTEMS_tasks_Allocate_and_prepare_stack( + Thread_Configuration *thread_config, + const rtems_task_config *config ) { - Thread_Control *the_thread; - Thread_Configuration config; -#if defined(RTEMS_MULTIPROCESSING) - Objects_MP_Control *the_global_object = NULL; - bool is_global; -#endif - bool status; - rtems_attribute the_attribute_set; - bool valid; - RTEMS_API_Control *api; - ASR_Information *asr; - - if ( !id ) - return RTEMS_INVALID_ADDRESS; - - if ( !rtems_is_name_valid( name ) ) - return RTEMS_INVALID_NAME; - - /* - * Core Thread Initialize insures we get the minimum amount of - * stack space. - */ - - /* - * Fix the attribute set to match the attributes which - * this processor (1) requires and (2) is able to support. - * First add in the required flags for attribute_set - * Typically this might include FP if the platform - * or application required all tasks to be fp aware. - * Then turn off the requested bits which are not supported. - */ - - the_attribute_set = _Attributes_Set( attribute_set, ATTRIBUTES_REQUIRED ); - the_attribute_set = - _Attributes_Clear( the_attribute_set, ATTRIBUTES_NOT_SUPPORTED ); - - memset( &config, 0, sizeof( config ) ); - config.budget_algorithm = _Modes_Is_timeslice( initial_modes ) ? - THREAD_CPU_BUDGET_ALGORITHM_RESET_TIMESLICE - : THREAD_CPU_BUDGET_ALGORITHM_NONE, - config.isr_level = _Modes_Get_interrupt_level( initial_modes ); - config.name.name_u32 = name; - config.is_fp = _Attributes_Is_floating_point( the_attribute_set ); - config.is_preemptible = _Modes_Is_preempt( initial_modes ); - config.stack_size = _Stack_Ensure_minimum( stack_size ); - config.stack_size = _Stack_Extend_size( config.stack_size, config.is_fp ); - - /* - * Validate the RTEMS API priority and convert it to the core priority range. - */ - - if ( !_Attributes_Is_system_task( the_attribute_set ) ) { - if ( initial_priority == PRIORITY_MINIMUM ) { - return RTEMS_INVALID_PRIORITY; - } - } - - config.scheduler = _Thread_Scheduler_get_home( _Thread_Get_executing() ); - - config.priority = _RTEMS_Priority_To_core( - config.scheduler, - initial_priority, - &valid - ); - if ( !valid ) { - return RTEMS_INVALID_PRIORITY; - } - -#if defined(RTEMS_MULTIPROCESSING) - if ( !_System_state_Is_multiprocessing ) { - the_attribute_set = _Attributes_Clear( the_attribute_set, RTEMS_GLOBAL ); - } - - is_global = _Attributes_Is_global( the_attribute_set ); -#endif - - /* - * Allocate the thread control block and -- if the task is global -- - * allocate a global object control block. - * - * NOTE: This routine does not use the combined allocate and open - * global object routine (_Objects_MP_Allocate_and_open) because - * this results in a lack of control over when memory is allocated - * and can be freed in the event of an error. - */ - the_thread = _RTEMS_tasks_Allocate(); - - if ( !the_thread ) { - _Objects_Allocator_unlock(); - return RTEMS_TOO_MANY; - } - -#if defined(RTEMS_MULTIPROCESSING) - if ( is_global ) { - the_global_object = _Objects_MP_Allocate_global_object(); - - if ( _Objects_MP_Is_null_global_object( the_global_object ) ) { - _RTEMS_tasks_Free( the_thread ); - _Objects_Allocator_unlock(); - return RTEMS_TOO_MANY; - } - } -#endif - - config.stack_free = _Stack_Free; - config.stack_area = _Stack_Allocate( config.stack_size ); - status = ( config.stack_area != NULL ); + size_t size; - /* - * Initialize the core thread for this task. - */ + thread_config->stack_free = _Stack_Free; + size = _Stack_Ensure_minimum( config->storage_size ); + size = _Stack_Extend_size( size, thread_config->is_fp ); + thread_config->stack_size = size; + thread_config->stack_area = _Stack_Allocate( size ); - if ( status ) { - status = _Thread_Initialize( - &_RTEMS_tasks_Information, - the_thread, - &config - ); - } - - if ( !status ) { -#if defined(RTEMS_MULTIPROCESSING) - if ( is_global ) - _Objects_MP_Free_global_object( the_global_object ); -#endif - _RTEMS_tasks_Free( the_thread ); - _Objects_Allocator_unlock(); + if ( thread_config->stack_area == NULL ) { return RTEMS_UNSATISFIED; } - api = the_thread->API_Extensions[ THREAD_API_RTEMS ]; - asr = &api->Signal; - - asr->is_enabled = _Modes_Is_asr_disabled(initial_modes) ? false : true; - - *id = the_thread->Object.id; - -#if defined(RTEMS_MULTIPROCESSING) - the_thread->is_global = is_global; - if ( is_global ) { - - _Objects_MP_Open( - &_RTEMS_tasks_Information.Objects, - the_global_object, - name, - the_thread->Object.id - ); - - _RTEMS_tasks_MP_Send_process_packet( - RTEMS_TASKS_MP_ANNOUNCE_CREATE, - the_thread->Object.id, - name - ); - - } -#endif - - _Objects_Allocator_unlock(); return RTEMS_SUCCESSFUL; } -static void _RTEMS_tasks_Start_extension( - Thread_Control *executing, - Thread_Control *started +rtems_status_code rtems_task_create( + rtems_name name, + rtems_task_priority initial_priority, + size_t stack_size, + rtems_mode initial_modes, + rtems_attribute attribute_set, + rtems_id *id ) { - RTEMS_API_Control *api; - - api = started->API_Extensions[ THREAD_API_RTEMS ]; - - _Event_Initialize( &api->Event ); - _Event_Initialize( &api->System_event ); -} + rtems_task_config config; -#if defined(RTEMS_MULTIPROCESSING) -static void _RTEMS_tasks_Terminate_extension( Thread_Control *executing ) -{ - if ( executing->is_global ) { - _Objects_MP_Close( - &_RTEMS_tasks_Information.Objects, - executing->Object.id - ); - _RTEMS_tasks_MP_Send_process_packet( - RTEMS_TASKS_MP_ANNOUNCE_DELETE, - executing->Object.id, - 0 /* Not used */ - ); - } -} -#endif - -static User_extensions_Control _RTEMS_tasks_User_extensions = { - .Callouts = { -#if defined(RTEMS_MULTIPROCESSING) - .thread_terminate = _RTEMS_tasks_Terminate_extension, -#endif - .thread_start = _RTEMS_tasks_Start_extension, - .thread_restart = _RTEMS_tasks_Start_extension - } -}; - -static void _RTEMS_tasks_Manager_initialization( void ) -{ - _Thread_Initialize_information( &_RTEMS_tasks_Information ); - _User_extensions_Add_API_set( &_RTEMS_tasks_User_extensions ); + memset( &config, 0, sizeof( config ) ); + config.name = name; + config.initial_priority = initial_priority; + config.storage_size = stack_size; + config.initial_modes = initial_modes; + config.attributes = attribute_set; + + return _RTEMS_tasks_Create( + &config, + id, + _RTEMS_tasks_Allocate_and_prepare_stack + ); } - -RTEMS_SYSINIT_ITEM( - _RTEMS_tasks_Manager_initialization, - RTEMS_SYSINIT_CLASSIC_TASKS, - RTEMS_SYSINIT_ORDER_MIDDLE -); diff --git a/spec/build/cpukit/librtemscpu.yml b/spec/build/cpukit/librtemscpu.yml index fa456b1db6..95322e027a 100644 --- a/spec/build/cpukit/librtemscpu.yml +++ b/spec/build/cpukit/librtemscpu.yml @@ -1276,6 +1276,7 @@ source: - cpukit/rtems/src/statustoerrno.c - cpukit/rtems/src/systemeventreceive.c - cpukit/rtems/src/systemeventsend.c +- cpukit/rtems/src/taskconstruct.c - cpukit/rtems/src/taskcreate.c - cpukit/rtems/src/taskdelete.c - cpukit/rtems/src/taskexit.c diff --git a/testsuites/sptests/sp01/init.c b/testsuites/sptests/sp01/init.c index 2719c84fc8..e0072a615c 100644 --- a/testsuites/sptests/sp01/init.c +++ b/testsuites/sptests/sp01/init.c @@ -16,6 +16,19 @@ const char rtems_test_name[] = "SP 1"; +RTEMS_ALIGNED( RTEMS_TASK_STORAGE_ALIGNMENT ) static char Task_1_storage[ + RTEMS_TASK_STORAGE_SIZE( 2 * RTEMS_MINIMUM_STACK_SIZE, RTEMS_FLOATING_POINT ) +]; + +static const rtems_task_config Task_1_config = { + .name = rtems_build_name( 'T', 'A', '1', ' ' ), + .initial_priority = 1, + .storage_area = Task_1_storage, + .storage_size = sizeof( Task_1_storage ), + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = RTEMS_FLOATING_POINT +}; + rtems_task Init( rtems_task_argument argument ) @@ -30,15 +43,8 @@ rtems_task Init( status = rtems_clock_set( &time ); directive_failed( status, "rtems_clock_set" ); - status = rtems_task_create( - rtems_build_name( 'T', 'A', '1', ' ' ), - 1, - RTEMS_MINIMUM_STACK_SIZE * 2, - RTEMS_DEFAULT_MODES, - RTEMS_DEFAULT_ATTRIBUTES, - &id - ); - directive_failed( status, "rtems_task_create of TA1" ); + status = rtems_task_construct( &Task_1_config, &id ); + directive_failed( status, "rtems_task_construct of TA1" ); status = rtems_task_start( id, Task_1_through_3, 1 ); directive_failed( status, "rtems_task_start of TA1" ); diff --git a/testsuites/sptests/sp01/sp01.doc b/testsuites/sptests/sp01/sp01.doc index d7d9f5d902..43c8ee0116 100644 --- a/testsuites/sptests/sp01/sp01.doc +++ b/testsuites/sptests/sp01/sp01.doc @@ -9,6 +9,7 @@ test name: sp01 directives: + rtems_task_construct rtems_task_create rtems_task_start rtems_task_wake_after diff --git a/testsuites/sptests/sp01/system.h b/testsuites/sptests/sp01/system.h index bde5328aa9..d7990aeca8 100644 --- a/testsuites/sptests/sp01/system.h +++ b/testsuites/sptests/sp01/system.h @@ -28,8 +28,9 @@ rtems_task Task_1_through_3( #define CONFIGURE_RTEMS_INIT_TASKS_TABLE -#define CONFIGURE_EXTRA_TASK_STACKS (4 * RTEMS_MINIMUM_STACK_SIZE) +#define CONFIGURE_EXTRA_TASK_STACKS (3 * RTEMS_MINIMUM_STACK_SIZE) #define CONFIGURE_MAXIMUM_TASKS 4 +#define CONFIGURE_MINIMUM_TASKS_WITH_USER_PROVIDED_STORAGE 1 #include -- cgit v1.2.3