diff options
Diffstat (limited to 'spec/rtems/task/req/construct.yml')
-rw-r--r-- | spec/rtems/task/req/construct.yml | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/spec/rtems/task/req/construct.yml b/spec/rtems/task/req/construct.yml new file mode 100644 index 00000000..3a4bfc28 --- /dev/null +++ b/spec/rtems/task/req/construct.yml @@ -0,0 +1,769 @@ +SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause +copyrights: +- Copyright (C) 2020, 2021 embedded brains GmbH (http://www.embedded-brains.de) +enabled-by: true +functional-type: action +links: +- role: interface-function + uid: ../if/construct +post-conditions: +- name: Status + states: + - name: Ok + test-code: | + T_rsc_success( ctx->status ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/successful:/name}. + - name: InvAddr + test-code: | + T_rsc( ctx->status, RTEMS_INVALID_ADDRESS ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/invalid-address:/name}. + - name: InvName + test-code: | + T_rsc( ctx->status, RTEMS_INVALID_NAME ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/invalid-name:/name}. + - name: InvPrio + test-code: | + T_rsc( ctx->status, RTEMS_INVALID_PRIORITY ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/invalid-priority:/name}. + - name: InvSize + test-code: | + T_rsc( ctx->status, RTEMS_INVALID_SIZE ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/invalid-size:/name}. + - name: TooMany + test-code: | + T_rsc( ctx->status, RTEMS_TOO_MANY ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/too-many:/name}. + - name: Unsat + test-code: | + T_rsc( ctx->status, RTEMS_UNSATISFIED ); + text: | + The return status of ${../if/construct:/name} shall be + ${../../status/if/unsatisfied:/name}. + test-epilogue: null + test-prologue: null +- name: Name + states: + - name: Valid + test-code: | + id = 0; + sc = rtems_task_ident( NAME, RTEMS_SEARCH_LOCAL_NODE, &id ); + T_rsc_success( sc ); + T_eq_u32( id, ctx->id_obj ); + text: | + The unique object name shall identify the task constructed by + the ${../if/construct:/name} call. + - name: Invalid + test-code: | + sc = rtems_task_ident( NAME, RTEMS_SEARCH_LOCAL_NODE, &id ); + T_rsc( sc, RTEMS_INVALID_NAME ); + text: | + The unique object name shall not identify a task. + test-epilogue: null + test-prologue: | + rtems_status_code sc; + rtems_id id; +- name: IdObj + states: + - name: Set + test-code: | + T_eq_ptr( ctx->id, &ctx->id_obj ); + T_ne_u32( ctx->id_obj, INVALID_ID ); + text: | + The value of the object referenced by the + ${../if/construct:/params[1]/name} parameter shall be set to the object + identifier of the constructed task after the return of the + ${../if/construct:/name} call. + - name: Nop + test-code: | + T_eq_u32( ctx->id_obj, INVALID_ID ); + text: | + Objects referenced by the ${../if/construct:/params[1]/name} parameter in + past calls to ${../if/construct:/name} shall not be accessed by the + ${../if/construct:/name} call. + test-epilogue: null + test-prologue: null +- name: CreateNew + states: + - name: All + test-code: | + T_eq_u32( ctx->create_extension_calls, 2 ); + text: | + The thread create user extensions shall be invoked for the task under + construction during the ${../if/construct:/name} call. + - name: UpToFailing + test-code: | + T_eq_u32( ctx->create_extension_calls, 1 ); + text: | + The thread create user extensions up to the failing extension shall be + invoked for the task under construction during the + ${../if/construct:/name} call. + - name: Nop + test-code: | + T_eq_u32( ctx->create_extension_calls, 0 ); + text: | + The thread create user extensions shall not be invoked for the task under + construction during the ${../if/construct:/name} call. + test-epilogue: null + test-prologue: null +- name: DeleteNew + states: + - name: All + test-code: | + T_eq_u32( ctx->delete_extension_calls, 2 ); + text: | + The thread delete user extensions shall be invoked for the task under + construction during the ${../if/construct:/name} call. + - name: Nop + test-code: | + T_eq_u32( ctx->delete_extension_calls, 0 ); + text: | + The thread delete user extensions shall not be invoked for the task under + construction during the ${../if/construct:/name} call. + test-epilogue: null + test-prologue: null +- name: KillZombies + states: + - name: 'Yes' + test-code: | + /* + * We cannot check the zombie delete extension calls if we should call + * rtems_task_construct() without an inactive TCB available. Killing + * a zombie would make one inactive TCB available. + */ + if ( ctx->seized_objects == NULL ) { + T_eq_u32( ctx->delete_zombie_extension_calls, 2 ); + } + text: | + The registered zombie threads shall be killed before an attempt to + allocate a ${/glossary/tcb:/term} is made by the ${../if/construct:/name} + call. + - name: 'No' + test-code: | + T_eq_u32( ctx->delete_zombie_extension_calls, 0 ); + text: | + The registered zombie threads shall not be killed by the + ${../if/construct:/name} call. + test-epilogue: null + test-prologue: null +- name: StorageFree + states: + - name: 'Yes' + test-code: | + T_eq_u32( ctx->storage_free_calls, 1 ); + text: | + The storage free handler of the task configuration shall be invoked + during the ${../if/construct:/name} call. + - name: 'No' + test-code: | + T_eq_u32( ctx->storage_free_calls, 0 ); + text: | + The storage free handler of the task configuration shall not be invoked + during the ${../if/construct:/name} call. + test-epilogue: null + test-prologue: null +pre-conditions: +- name: Config + states: + - name: Valid + test-code: | + ctx->config = &ctx->config_obj; + text: | + While the ${../if/construct:/params[0]/name} parameter references an + object of type ${../if/config:/name}. + - name: 'Null' + test-code: | + ctx->config = NULL; + text: | + While the ${../if/construct:/params[0]/name} parameter is + ${/c/if/null:/name}. + test-epilogue: null + test-prologue: null +- name: Name + states: + - name: Valid + test-code: | + ctx->config_obj.name = NAME; + text: | + While the name of the task configuration is valid. + - name: Invalid + test-code: | + ctx->config_obj.name = 0; + text: | + While the name of the task configuration is invalid. + test-epilogue: null + test-prologue: null +- name: Id + states: + - name: Valid + test-code: | + ctx->id = &ctx->id_obj; + text: | + While the ${../if/construct:/params[1]/name} parameter references an + object of type ${../../type/if/id:/name}. + - name: 'Null' + test-code: | + ctx->id = NULL; + text: | + While the ${../if/construct:/params[1]/name} parameter is + ${/c/if/null:/name}. + test-epilogue: null + test-prologue: null +- name: SystemTask + states: + - name: 'Yes' + test-code: | + ctx->config_obj.attributes |= RTEMS_SYSTEM_TASK; + text: | + While the attributes of the task configuration specifies a system task. + - name: 'No' + test-code: | + /* Nothing to do */ + text: | + While the attributes of the task configuration specifies an application + task. + test-epilogue: null + test-prologue: null +- name: Priority + states: + - name: Valid + test-code: | + ctx->config_obj.initial_priority = 254; + text: | + While the initial priority of the task configuration is valid and + non-zero. + - name: Zero + test-code: | + ctx->config_obj.initial_priority = 0; + text: | + While the initial priority of the task configuration is zero. + - name: Invalid + test-code: | + ctx->config_obj.initial_priority = 0xffffffff; + text: | + While the initial priority of the task configuration is invalid. + test-epilogue: null + test-prologue: null +- name: Free + states: + - name: 'Yes' + test-code: | + /* Nothing to do */ + text: | + While the system has at least one inactive task object available. + - name: 'No' + test-code: | + ctx->seized_objects = T_seize_objects( Create, ctx ); + text: | + While the system has no inactive task object available. + test-epilogue: null + test-prologue: null +- name: TLS + states: + - name: Enough + test-code: | + ctx->config_obj.maximum_thread_local_storage_size = MAX_TLS_SIZE; + text: | + While the maximum thread-local storage size of the task configuration is + greater than or equal to the thread-local storage size. + - name: TooSmall + test-code: | + ctx->config_obj.maximum_thread_local_storage_size = 0; + text: | + While the maximum thread-local storage size of the task configuration is + less than the thread-local storage size. + test-epilogue: null + test-prologue: null +- name: Stack + states: + - name: Enough + test-code: | + ctx->stack_size = RTEMS_MINIMUM_STACK_SIZE; + text: | + While the task stack size of the task configuration is greater than or + equal to the configured minimum size. + - name: TooSmall + test-code: | + ctx->stack_size = 0; + text: | + While the task stack size of the task configuration is less than the + configured minimum size. + test-epilogue: null + test-prologue: null +- name: Create + states: + - name: Ok + test-code: | + ctx->create_extension_status = true; + text: | + While none of the thread create user extensions fails. + - name: Error + test-code: | + ctx->create_extension_status = false; + text: | + While at least one of the thread create user extensions fails. + test-epilogue: null + test-prologue: null +rationale: null +references: [] +requirement-type: functional +skip-reasons: {} +test-action: | + if ( ctx->seized_objects == NULL ) { + PrepareZombie( ctx ); + } + + ctx->create_extension_calls = 0; + ctx->delete_extension_calls = 0; + ctx->delete_zombie_extension_calls = 0; + ctx->storage_free_calls = 0; + ctx->config_obj.storage_size = RTEMS_TASK_STORAGE_SIZE( + ctx->config_obj.maximum_thread_local_storage_size + ctx->stack_size, + ctx->config_obj.attributes + ); + ctx->status = rtems_task_construct( ctx->config, ctx->id ); +test-brief: null +test-cleanup: | + if ( ctx->id_obj != INVALID_ID ) { + rtems_status_code sc; + + sc = rtems_task_delete( ctx->id_obj ); + T_rsc_success( sc ); + + ctx->id_obj = INVALID_ID; + } + + T_surrender_objects( &ctx->seized_objects, rtems_task_delete ); +test-context: +- brief: | + This member contains the scheduler B identifier. + description: null + member: | + rtems_id scheduler_b_id +- brief: | + This member contains the thread zombie registry ticket right before the + task exit of the zombie task. + description: null + member: | + unsigned int thread_zombie_ticket +- brief: | + If this member is true, then the zombie thread is ready to get killed. + description: null + member: | + volatile bool zombie_ready; +- brief: null + description: null + member: | + rtems_status_code status +- brief: null + description: null + member: | + const rtems_task_config *config +- brief: null + description: null + member: | + rtems_task_config config_obj +- brief: null + description: null + member: | + rtems_id zombie_id +- brief: null + description: null + member: | + rtems_id *id +- brief: null + description: null + member: | + rtems_id id_obj +- brief: null + description: null + member: | + bool create_extension_status +- brief: null + description: null + member: | + uint32_t create_extension_calls +- brief: null + description: null + member: | + uint32_t delete_extension_calls +- brief: null + description: null + member: | + uint32_t delete_zombie_extension_calls +- brief: null + description: null + member: | + uint32_t storage_free_calls +- brief: null + description: null + member: | + size_t stack_size +- brief: null + description: null + member: | + rtems_id extension_ids[ 2 ] +- brief: null + description: null + member: | + void *seized_objects +test-context-support: null +test-description: null +test-header: null +test-includes: +- rtems.h +- rtems/score/atomic.h +- rtems/score/percpu.h +- rtems/score/threadimpl.h +- string.h +test-local-includes: +- ts-config.h +- tx-support.h +test-prepare: | + KillZombies(); + ctx->id_obj = INVALID_ID; + memset( &ctx->config_obj, 0, sizeof( ctx->config_obj ) ); + ctx->config_obj.storage_area = task_storage, + ctx->config_obj.storage_free = StorageFree; +test-setup: + brief: null + code: | + rtems_status_code sc; + int var; + + var = tls_object; + RTEMS_OBFUSCATE_VARIABLE( var ); + tls_object = var; + + ctx->scheduler_b_id = INVALID_ID; + #if defined(RTEMS_SMP) + ctx->zombie_ready = true; + if ( rtems_scheduler_get_processor_maximum() > 1 ) { + sc = rtems_scheduler_ident( + TEST_SCHEDULER_B_NAME, + &ctx->scheduler_b_id + ); + T_rsc_success( sc ); + } + #endif + + sc = rtems_extension_create( + rtems_build_name( 'E', 'X', 'T', '1' ), + &extensions[ 0 ], + &ctx->extension_ids[ 0 ] + ); + T_rsc_success( sc ); + + sc = rtems_extension_create( + rtems_build_name( 'E', 'X', 'T', '2' ), + &extensions[ 1 ], + &ctx->extension_ids[ 1 ] + ); + T_rsc_success( sc ); + + SetSelfPriority( PRIO_NORMAL ); + description: null +test-stop: null +test-support: | + #define NAME rtems_build_name( 'T', 'E', 'S', 'T' ) + + typedef RtemsTaskReqConstruct_Context Context; + + static volatile _Thread_local int tls_object; + + #define MAX_TLS_SIZE RTEMS_ALIGN_UP( 128, RTEMS_TASK_STORAGE_ALIGNMENT ) + + RTEMS_ALIGNED( RTEMS_TASK_STORAGE_ALIGNMENT ) static char task_storage[ + RTEMS_TASK_STORAGE_SIZE( + MAX_TLS_SIZE + RTEMS_MINIMUM_STACK_SIZE, + RTEMS_FLOATING_POINT + ) + ]; + + static const rtems_task_config seize_task_config = { + .name = rtems_build_name( 'S', 'I', 'Z', 'E' ), + .initial_priority = 1, + .storage_area = task_storage, + .storage_size = sizeof( task_storage ), + .maximum_thread_local_storage_size = MAX_TLS_SIZE, + .initial_modes = RTEMS_DEFAULT_MODES, + .attributes = RTEMS_DEFAULT_MODES + }; + + static void StorageFree( void *ptr ) + { + T_eq_ptr( ptr, task_storage ); + ++RtemsTaskReqConstruct_Instance.storage_free_calls; + } + + static rtems_status_code Create( void *arg, uint32_t *id ) + { + Context *ctx; + bool create_extension_status; + rtems_status_code sc; + + ctx = arg; + create_extension_status = ctx->create_extension_status; + ctx->create_extension_status = true; + sc = rtems_task_construct( &seize_task_config, id ); + ctx->create_extension_status = create_extension_status; + + return sc; + } + + static bool ThreadCreate( rtems_tcb *executing, rtems_tcb *created ) + { + (void) executing; + (void) created; + + ++RtemsTaskReqConstruct_Instance.create_extension_calls; + return RtemsTaskReqConstruct_Instance.create_extension_status; + } + + static bool SecondThreadCreate( rtems_tcb *executing, rtems_tcb *created ) + { + (void) executing; + (void) created; + + ++RtemsTaskReqConstruct_Instance.create_extension_calls; + return true; + } + + static void ThreadDelete( rtems_tcb *executing, rtems_tcb *deleted ) + { + Context *ctx; + + (void) executing; + + ctx = &RtemsTaskReqConstruct_Instance; + + if ( deleted->Object.id == ctx->zombie_id ) { + ++ctx->delete_zombie_extension_calls; + } else { + ++ctx->delete_extension_calls; + } + } + + #if defined(RTEMS_SMP) + static void PreemptionIntervention( void *arg ) + { + Context *ctx; + unsigned int ticket; + + ctx = arg; + T_false( ctx->zombie_ready ); + ctx->zombie_ready = true; + + do { + ticket = _Atomic_Load_uint( + &_Thread_Zombies.Lock.Lock.Ticket_lock.now_serving, + ATOMIC_ORDER_RELAXED + ); + } while ( ( ticket - ctx->thread_zombie_ticket ) < 2 ); + + T_busy( 100 ); + } + + static void ThreadTerminate( rtems_tcb *executing ) + { + Context *ctx; + + ctx = &RtemsTaskReqConstruct_Instance; + + if ( + ctx->scheduler_b_id != INVALID_ID && + ctx->zombie_id == executing->Object.id + ) { + /* + * We use the ticket lock of the thread zombie registry to delay the thread + * dispatch and provoke an executing thread in + * _Thread_Kill_zombies(). The first acquire is done in the + * rtems_task_exit() below. The second acquire is done in + * _Thread_Kill_zombies(). + */ + ctx->thread_zombie_ticket = _Atomic_Fetch_add_uint( + &_Thread_Zombies.Lock.Lock.Ticket_lock.now_serving, + 0, + ATOMIC_ORDER_RELAXED + ); + SetPreemptionIntervention( + _Per_CPU_Get_snapshot(), + PreemptionIntervention, + ctx + ); + } + } + #endif + + static const rtems_extensions_table extensions[] = { + { + #if defined(RTEMS_SMP) + .thread_terminate = ThreadTerminate, + #endif + .thread_create = ThreadCreate, + .thread_delete = ThreadDelete + }, { + .thread_create = SecondThreadCreate, + .thread_delete = ThreadDelete + } + }; + + static void ZombieTask( rtems_task_argument arg ) + { + (void) arg; + rtems_task_exit(); + } + + static void PrepareZombie( Context *ctx ) + { + bool create_extension_status; + + create_extension_status = ctx->create_extension_status; + ctx->create_extension_status = true; + ctx->zombie_id = CreateTask( "ZOMB", PRIO_HIGH ); + ctx->create_extension_status = create_extension_status; + #if defined(RTEMS_SMP) + if ( ctx->scheduler_b_id != INVALID_ID ) { + ctx->zombie_ready = false; + SetScheduler( ctx->zombie_id, ctx->scheduler_b_id, PRIO_NORMAL ); + } + #endif + StartTask( ctx->zombie_id, ZombieTask, ctx ); + #if defined(RTEMS_SMP) + while ( !ctx->zombie_ready ) { + /* Wait */ + } + #endif + } +test-target: testsuites/validation/tc-task-construct.c +test-teardown: + brief: null + code: | + rtems_status_code sc; + + sc = rtems_extension_delete( ctx->extension_ids[ 0 ] ); + T_rsc_success( sc ); + + sc = rtems_extension_delete( ctx->extension_ids[ 1 ] ); + T_rsc_success( sc ); + + RestoreRunnerPriority(); + description: null +text: ${.:text-template} +transition-map: +- enabled-by: true + post-conditions: + Status: + - if: + pre-conditions: + Config: 'Null' + then: InvAddr + - if: + pre-conditions: + Name: Invalid + then: InvName + - if: + pre-conditions: + Id: 'Null' + then: InvAddr + - if: + pre-conditions: + Priority: Zero + SystemTask: 'No' + then: InvPrio + - if: + pre-conditions: + Priority: Invalid + then: InvPrio + - if: + pre-conditions: + Free: 'No' + then: TooMany + - if: + pre-conditions: + TLS: TooSmall + then: InvSize + - if: + pre-conditions: + Stack: TooSmall + then: InvSize + - if: + pre-conditions: + Create: Error + then: Unsat + - else: Ok + Name: + - if: + post-conditions: + Status: Ok + then: Valid + - else: Invalid + IdObj: + - if: + post-conditions: + Status: Ok + then: Set + - else: Nop + CreateNew: + - if: + post-conditions: + Status: Ok + then: All + - if: + post-conditions: + Status: Unsat + then: UpToFailing + - else: Nop + DeleteNew: + - if: + post-conditions: + Status: Unsat + then: All + - else: Nop + KillZombies: + - if: + - pre-conditions: + Config: Valid + Name: Valid + Id: Valid + SystemTask: 'Yes' + Priority: + - Valid + - Zero + - pre-conditions: + Config: Valid + Name: Valid + Id: Valid + SystemTask: 'No' + Priority: + - Valid + then: 'Yes' + - else: 'No' + StorageFree: + - if: + post-conditions: + Status: Unsat + then: 'Yes' + - else: 'No' + pre-conditions: + Config: all + Create: all + Id: all + Name: all + SystemTask: all + Priority: all + Stack: all + TLS: all + Free: all +type: requirement |