From 8293cd477996ef7797a234e1fa2a0aa47ee6d3bd Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 13 Aug 2021 09:52:04 +0200 Subject: spec: Improve rtems_task_construct() validation Call rtems_task_construct() with a zombie thread if it should be called with at least one inactive task available. Try to make the zombie thread executing in SMP configurations. --- spec/rtems/task/req/construct-errors.yml | 592 ------------------------ spec/rtems/task/req/construct.yml | 769 +++++++++++++++++++++++++++++++ 2 files changed, 769 insertions(+), 592 deletions(-) delete mode 100644 spec/rtems/task/req/construct-errors.yml create mode 100644 spec/rtems/task/req/construct.yml (limited to 'spec/rtems/task/req') diff --git a/spec/rtems/task/req/construct-errors.yml b/spec/rtems/task/req/construct-errors.yml deleted file mode 100644 index de595c14..00000000 --- a/spec/rtems/task/req/construct-errors.yml +++ /dev/null @@ -1,592 +0,0 @@ -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_value ); - 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: IdVar - states: - - name: Set - test-code: | - T_eq_ptr( ctx->id, &ctx->id_value ); - T_ne_u32( ctx->id_value, 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_value, 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: CreateExt - states: - - name: All - test-code: | - T_eq_u32( ctx->create_extension_calls, 2 ); - text: | - The create user extensions shall be invoked during the - ${../if/construct:/name} call. - - name: UpToFailing - test-code: | - T_eq_u32( ctx->create_extension_calls, 1 ); - text: | - The create user extensions up to the failing extension shall be invoked - during the ${../if/construct:/name} call. - - name: 'No' - test-code: | - T_eq_u32( ctx->create_extension_calls, 0 ); - text: | - The create user extensions shall not be invoked during the - ${../if/construct:/name} call. - test-epilogue: null - test-prologue: null -- name: DelExt - states: - - name: 'Yes' - test-code: | - T_eq_u32( ctx->delete_extension_calls, 2 ); - text: | - The delete user extensions shall be invoked during the - ${../if/construct:/name} call. - - name: 'No' - test-code: | - T_eq_u32( ctx->delete_extension_calls, 0 ); - text: | - The delete user extensions shall not be invoked during the - ${../if/construct:/name} call. - test-epilogue: null - test-prologue: null -- name: StoFree - 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_value; - 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_value.name = NAME; - text: | - While the name of the task configuration is valid. - - name: Inv - test-code: | - ctx->config_value.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_value; - 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: SysTsk - states: - - name: 'Yes' - test-code: | - ctx->config_value.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: Prio - states: - - name: Valid - test-code: | - ctx->config_value.initial_priority = 254; - text: | - While the initial priority of the task configuration is valid and - non-zero. - - name: Zero - test-code: | - ctx->config_value.initial_priority = 0; - text: | - While the initial priority of the task configuration is zero. - - name: Inv - test-code: | - ctx->config_value.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_value.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: Small - test-code: | - ctx->config_value.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: Small - 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: Ext - states: - - name: Ok - test-code: | - ctx->create_extension_status = true; - text: | - While none of the task create extensions fails. - - name: Err - test-code: | - ctx->create_extension_status = false; - text: | - While at least one of the task create extensions fails. - test-epilogue: null - test-prologue: null -rationale: null -references: [] -requirement-type: functional -skip-reasons: {} -test-action: | - ctx->create_extension_calls = 0; - ctx->delete_extension_calls = 0; - ctx->storage_free_calls = 0; - ctx->config_value.storage_size = RTEMS_TASK_STORAGE_SIZE( - ctx->config_value.maximum_thread_local_storage_size + ctx->stack_size, - ctx->config_value.attributes - ); - ctx->status = rtems_task_construct( ctx->config, ctx->id ); -test-brief: null -test-cleanup: | - if ( ctx->id_value != INVALID_ID ) { - rtems_status_code sc; - - sc = rtems_task_delete( ctx->id_value ); - T_rsc_success( sc ); - - ctx->id_value = INVALID_ID; - } - - T_surrender_objects( &ctx->seized_objects, rtems_task_delete ); -test-context: -- 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_value -- brief: null - description: null - member: | - rtems_id *id -- brief: null - description: null - member: | - rtems_id id_value -- 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 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 -- string.h -- rtems/score/apimutex.h -- rtems/score/threadimpl.h -test-local-includes: -- tx-support.h -test-prepare: | - _RTEMS_Lock_allocator(); - _Thread_Kill_zombies(); - _RTEMS_Unlock_allocator(); - - ctx->id_value = INVALID_ID; - memset( &ctx->config_value, 0, sizeof( ctx->config_value ) ); - ctx->config_value.storage_area = task_storage, - ctx->config_value.storage_free = StorageFree; -test-setup: - brief: null - code: | - rtems_status_code sc; - int var; - - var = tls_variable; - RTEMS_OBFUSCATE_VARIABLE( var ); - tls_variable = var; - - 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 ); - description: null -test-stop: null -test-support: | - #define NAME rtems_build_name( 'T', 'E', 'S', 'T' ) - - typedef RtemsTaskReqConstructErrors_Context Context; - - static _Thread_local int tls_variable; - - #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 ); - ++RtemsTaskReqConstructErrors_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; - - ++RtemsTaskReqConstructErrors_Instance.create_extension_calls; - return RtemsTaskReqConstructErrors_Instance.create_extension_status; - } - - static bool SecondThreadCreate( rtems_tcb *executing, rtems_tcb *created ) - { - (void) executing; - (void) created; - - ++RtemsTaskReqConstructErrors_Instance.create_extension_calls; - return true; - } - - static void ThreadDelete( rtems_tcb *executing, rtems_tcb *deleted ) - { - (void) executing; - (void) deleted; - - ++RtemsTaskReqConstructErrors_Instance.delete_extension_calls; - } - - static const rtems_extensions_table extensions[] = { - { - .thread_create = ThreadCreate, - .thread_delete = ThreadDelete - }, { - .thread_create = SecondThreadCreate, - .thread_delete = ThreadDelete - } - }; -test-target: testsuites/validation/tc-task-construct-errors.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 ); - description: null -text: ${.:text-template} -transition-map: -- enabled-by: true - post-conditions: - Status: - - if: - pre-conditions: - Config: 'Null' - then: InvAddr - - if: - pre-conditions: - Name: Inv - then: InvName - - if: - pre-conditions: - Id: 'Null' - then: InvAddr - - if: - pre-conditions: - Prio: Zero - SysTsk: 'No' - then: InvPrio - - if: - pre-conditions: - Prio: Inv - then: InvPrio - - if: - pre-conditions: - Free: 'No' - then: TooMany - - if: - pre-conditions: - TLS: Small - then: InvSize - - if: - pre-conditions: - Stack: Small - then: InvSize - - if: - pre-conditions: - Ext: Err - then: Unsat - - else: Ok - Name: - - if: - post-conditions: - Status: Ok - then: Valid - - else: Invalid - IdVar: - - if: - post-conditions: - Status: Ok - then: Set - - else: Nop - CreateExt: - - if: - post-conditions: - Status: Ok - then: All - - if: - post-conditions: - Status: Unsat - then: UpToFailing - - else: 'No' - DelExt: - - if: - post-conditions: - Status: Unsat - then: 'Yes' - - else: 'No' - StoFree: - - if: - post-conditions: - Status: Unsat - then: 'Yes' - - else: 'No' - pre-conditions: - Config: all - Ext: all - Id: all - Name: all - SysTsk: all - Prio: all - Stack: all - TLS: all - Free: all -type: requirement 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 -- cgit v1.2.3