diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-04-09 12:12:13 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2020-09-17 17:42:25 +0200 |
commit | 6942e5f99171d1cb38c2c573aba8cb9212d7efd8 (patch) | |
tree | f49a2afc076013602f4d437784391415cb6ed6a6 /cpukit/rtems | |
parent | c312f3110ebd6b38c3971910fe034b6c97ebb28c (diff) |
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.
Diffstat (limited to 'cpukit/rtems')
-rw-r--r-- | cpukit/rtems/src/taskconstruct.c | 300 | ||||
-rw-r--r-- | cpukit/rtems/src/taskcreate.c | 282 |
2 files changed, 357 insertions, 225 deletions
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 <rtems/rtems/tasksimpl.h> +#include <rtems/rtems/attrimpl.h> +#include <rtems/rtems/eventimpl.h> +#include <rtems/rtems/modesimpl.h> +#include <rtems/rtems/support.h> +#include <rtems/score/apimutex.h> +#include <rtems/score/schedulerimpl.h> +#include <rtems/score/stackimpl.h> +#include <rtems/score/threadimpl.h> +#include <rtems/score/userextimpl.h> +#include <rtems/sysinit.h> + +#include <string.h> + +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 <rtems/rtems/tasksimpl.h> -#include <rtems/rtems/attrimpl.h> -#include <rtems/rtems/eventimpl.h> -#include <rtems/rtems/modesimpl.h> -#include <rtems/rtems/support.h> -#include <rtems/score/apimutex.h> -#include <rtems/score/schedulerimpl.h> #include <rtems/score/stackimpl.h> -#include <rtems/score/sysstate.h> -#include <rtems/score/threadimpl.h> -#include <rtems/score/userextimpl.h> -#include <rtems/sysinit.h> #include <string.h> -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 -); |