SPDX-License-Identifier: CC-BY-SA-4.0 OR BSD-2-Clause copyrights: - Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) enabled-by: true functional-type: action links: - role: interface-function uid: ../if/cancel post-conditions: - name: Status states: - name: Ok test-code: | T_rsc_success( ctx->status ); text: | The return status of ${../if/cancel:/name} shall be ${../../status/if/successful:/name} - name: InvId test-code: | T_rsc( ctx->status, RTEMS_INVALID_ID ); text: | The return status of ${../if/cancel:/name} shall be ${../../status/if/invalid-id:/name}. - name: NotOwn test-code: | T_rsc( ctx->status, RTEMS_NOT_OWNER_OF_RESOURCE ); text: | The return status of ${../if/cancel:/name} shall be ${../../status/if/not-owner-of-resource:/name}. test-epilogue: null test-prologue: null - name: State states: - name: Inactive test-code: | T_eq_int( ctx->period_status.state, RATE_MONOTONIC_INACTIVE ); text: | The ${../glossary/state:/term} of the period shall be ${../glossary/inactive:/term} after the return of the ${../if/cancel:/name} call. - name: Nop test-code: | T_eq_u32( ctx->period_status.state, ctx->previous_state ); text: | Objects referenced by the ${../if/cancel:/params[0]/name} parameter in past calls to ${../if/cancel:/name} shall not be accessed by the ${../if/cancel:/name} call (see also ${../glossary/nop:/term}). test-epilogue: null test-prologue: null - name: Postponed states: - name: Zero test-code: | T_eq_u32( ctx->period_status.postponed_jobs_count, 0 ); text: | There shall be no ${../glossary/postponedjob:/plural} after the return of the ${../if/cancel:/name} call. - name: Nop test-code: | T_eq_u32( ctx->period_status.postponed_jobs_count, ctx->postponed_jobs_count ); text: | Objects referenced by the ${../if/cancel:/params[0]/name} parameter in past calls to ${../if/cancel:/name} shall not be accessed by the ${../if/cancel:/name} call (see also ${../glossary/nop:/term}). test-epilogue: null test-prologue: null - name: Scheduler states: - name: Called test-code: | /* Cannot be tested as the effect is unknown. */ text: | The last call of the ${../if/cancel:/name} function shall execute the ``cancel_job`` ${../glossary/scheduleroperation:/term} of the ${/glossary/scheduler-home:/term}. - name: Nop test-code: | /* Cannot be tested as the effect is unknown. */ text: | The last call of the ${../if/cancel:/name} function shall not execute any ${../glossary/scheduleroperation:/term}. test-epilogue: null test-prologue: null pre-conditions: - name: Id states: - name: Valid test-code: | ctx->id_param = ctx->period_id; text: | While the ${../if/cancel:/params[0]/name} parameter is valid. - name: Invalid test-code: | ctx->id_param = RTEMS_ID_NONE; text: | While the ${../if/cancel:/params[0]/name} parameter is invalid. test-epilogue: null test-prologue: null - name: Caller states: - name: OwnerTask test-code: | ctx->do_action = Action; text: | While the ${/glossary/task:/term} invoking ${../if/cancel:/name} is the ${/glossary/task:/term} which created the period - the ${../glossary/ownertask:/term}. - name: OtherTask test-code: | ctx->do_action = WorkerTaskAction; text: | While the ${/glossary/task:/term} invoking ${../if/cancel:/name} is not the ${../glossary/ownertask:/term}. test-epilogue: null test-prologue: null - name: State states: - name: Inactive test-code: | /* Nothing to do here as the period is newly created. */ ctx->previous_state = RATE_MONOTONIC_INACTIVE; text: | While the ${../if/cancel:/params[0]/name} parameter references an period object in ${../glossary/inactive:/term} ${../glossary/state:/term}. - name: Active test-code: | rtems_status_code status; status = rtems_rate_monotonic_period( ctx->period_id, period_length ); T_rsc_success( status ); ctx->previous_state = RATE_MONOTONIC_ACTIVE; text: | While the ${../if/cancel:/params[0]/name} parameter references an period object in ${../glossary/active:/term} ${../glossary/state:/term}. - name: Expired test-code: | rtems_status_code status; status = rtems_rate_monotonic_period( ctx->period_id, period_length ); T_rsc_success( status ); ctx->previous_state = RATE_MONOTONIC_EXPIRED; text: | While the ${../if/cancel:/params[0]/name} parameter references an period object in ${../glossary/expired:/term} ${../glossary/state:/term}. test-epilogue: null test-prologue: null - name: Postponed states: - name: Zero test-code: | ctx->postponed_jobs_count = 0; text: | While the period is not in ${../glossary/expired:/term} ${../glossary/state:/term}. - name: One test-code: | CreatePostponedJobs( ctx, 1 ); text: | While there is one ${../glossary/postponedjob:/term}. - name: Several test-code: | CreatePostponedJobs( ctx, 5 ); text: | While there are two or more ${../glossary/postponedjob:/plural}. test-epilogue: null test-prologue: null rationale: null references: [] requirement-type: functional skip-reasons: NotInInactiveState: | ${../glossary/postponedjob:/plural} do not exist in ${../glossary/inactive:/term} ${../glossary/state:/term}. NeverInExpiredState: | There must be ${../glossary/postponedjob:/plural} in ${../glossary/expired:/term} ${../glossary/state:/term}. test-action: | rtems_status_code status; ctx->do_action( ctx ); status = rtems_rate_monotonic_get_status( ctx->period_id, &ctx->period_status ); T_rsc_success( status ); test-brief: null test-cleanup: | T_rsc_success( rtems_rate_monotonic_delete( ctx->period_id ) ); test-context: - brief: | This member contains a valid identifier of a period. description: null member: | rtems_id period_id - brief: | This member is used to receive the ${../if/period-status:/name} after the action. description: null member: | rtems_rate_monotonic_period_status period_status - brief: | This member specifies the ${../if/cancel:/params[0]/name} parameter for the action. description: null member: | rtems_id id_param - brief: | This member contains the returned ${/glossary/statuscode:/term} of the action. description: null member: | rtems_status_code status - brief: | This member contains the pointer to the function which executes the action. description: | The action is either executed by the ${../glossary/ownertask:/term} or by the worker ${/glossary/task:/term} depending on the function pointer used here. ``argument`` is a pointer to this context structure. member: | void ( *do_action )( void *ctx ) - brief: | This member contains the ${/glossary/task:/term} identifier of the ${../glossary/ownertask:/term}. description: null member: | rtems_id task_id - brief: | This member contains the ${/glossary/task:/term} identifier of the worker ${/glossary/task:/term} (which is not the ${../glossary/ownertask:/term}). description: null member: | rtems_id worker_id - brief: | This member contains a backup of the ${/glossary/priority-task:/term} before the execution of this test. description: null member: | rtems_id original_priority - brief: | This member contains the number of ${../glossary/postponedjob:/plural} before the action. description: null member: | uint32_t postponed_jobs_count - brief: | This member contains the ${../glossary/state:/term} before the action. description: null member: | rtems_rate_monotonic_period_states previous_state test-context-support: null test-description: null test-header: null test-includes: - rtems.h test-local-includes: - tx-support.h test-prepare: | rtems_status_code status; status = rtems_rate_monotonic_create( rtems_build_name( 'R', 'M', 'O', 'N' ), &ctx->period_id ); T_rsc_success( status ); ctx->postponed_jobs_count = 0; test-setup: brief: null code: | rtems_status_code status; rtems_task_priority priority; rtems_event_set event_set; ctx->worker_id = RTEMS_INVALID_ID; status = rtems_task_ident( RTEMS_SELF, RTEMS_SEARCH_ALL_NODES, &ctx->task_id ); T_rsc_success( status ); status = rtems_task_set_priority( RTEMS_SELF, RTEMS_CURRENT_PRIORITY, &ctx->original_priority ); T_rsc_success( status ); status = rtems_task_set_priority( RTEMS_SELF, background_task_priority, &priority ); T_rsc_success( status ); status = rtems_task_create( rtems_build_name( 'W', 'O', 'R', 'K' ), foreground_task_priority, RTEMS_MINIMUM_STACK_SIZE, RTEMS_DEFAULT_MODES, RTEMS_DEFAULT_ATTRIBUTES, &ctx->worker_id ); T_rsc_success( status ); /* Defensive programming: clean away any pending events */ status = rtems_event_receive( RTEMS_ALL_EVENTS, RTEMS_NO_WAIT | RTEMS_EVENT_ANY, RTEMS_NO_TIMEOUT, &event_set ); T_true( status == RTEMS_SUCCESSFUL || status == RTEMS_UNSATISFIED ); status = rtems_task_start( ctx->worker_id, WorkerTask, (rtems_task_argument) NULL ); T_rsc_success( status ); description: null test-stop: null test-support: | static const rtems_interval period_length = 5; static const rtems_task_priority background_task_priority = 100; static const rtems_task_priority foreground_task_priority = 10; static const rtems_event_set wake_main_task_event = RTEMS_EVENT_17; static void TickTheClock( RtemsRatemonReqCancel_Context *ctx, uint32_t ticks ) { uint32_t i; for ( i = 0; i < ticks; ++i ) { TimecounterTick(); } } static void Action( void *ctx_in ) { RtemsRatemonReqCancel_Context *ctx = ctx_in; ctx->status = rtems_rate_monotonic_cancel( ctx->id_param ); } static void WorkerTask( rtems_task_argument argument ) { RtemsRatemonReqCancel_Context *ctx = (RtemsRatemonReqCancel_Context *) argument; if ( ctx != NULL ) { Action( ctx ); T_rsc_success( rtems_event_send( ctx->task_id, wake_main_task_event ) ); } T_rsc_success( rtems_task_suspend( RTEMS_SELF ) ); } static void WorkerTaskAction( void *ctx_in ) { rtems_status_code status; rtems_event_set event_set; RtemsRatemonReqCancel_Context *ctx = ctx_in; status = rtems_task_restart( ctx->worker_id, (rtems_task_argument) ctx ); T_rsc_success( status ); /* Wait till the worker task finishes */ status = rtems_event_receive( wake_main_task_event, RTEMS_DEFAULT_OPTIONS, RTEMS_NO_TIMEOUT, &event_set ); T_rsc_success( status ); } static void CreatePostponedJobs( RtemsRatemonReqCancel_Context *ctx, uint32_t jobs_count ) { rtems_status_code status; ctx->postponed_jobs_count = jobs_count; if ( ctx->previous_state == RATE_MONOTONIC_ACTIVE ) { TickTheClock( ctx, ( jobs_count + 1 ) * period_length ); status = rtems_rate_monotonic_period( ctx->period_id, period_length ); T_rsc( status, RTEMS_TIMEOUT ); } else { /* ctx->previous_state == RATE_MONOTONIC_INACTIVE || _EXPIRED */ TickTheClock( ctx, jobs_count * period_length ); } } test-target: testsuites/validation/tc-ratemon-cancel.c test-teardown: brief: null code: | rtems_status_code status; rtems_task_priority priority; T_rsc_success( rtems_task_delete( ctx->worker_id ) ); status = rtems_task_set_priority( RTEMS_SELF, ctx->original_priority, &priority ); T_rsc_success( status ); description: null text: ${.:text-template} transition-map: - enabled-by: true post-conditions: Status: Ok State: Inactive Postponed: N/A Scheduler: Called pre-conditions: Id: - Valid Caller: - OwnerTask State: - Inactive Postponed: N/A - enabled-by: true post-conditions: Status: Ok State: Inactive Postponed: Zero Scheduler: Called pre-conditions: Id: - Valid Caller: - OwnerTask State: - Active - Expired Postponed: all - enabled-by: true post-conditions: Status: InvId State: Nop Postponed: Nop Scheduler: Nop pre-conditions: Id: - Invalid Caller: all State: - Inactive Postponed: N/A - enabled-by: true post-conditions: Status: InvId State: Nop Postponed: Nop Scheduler: Nop pre-conditions: Id: - Invalid Caller: all State: - Active - Expired Postponed: all - enabled-by: true post-conditions: Status: NotOwn State: Nop Postponed: Nop Scheduler: Nop pre-conditions: Id: - Valid Caller: - OtherTask State: - Inactive Postponed: N/A - enabled-by: true post-conditions: Status: NotOwn State: Nop Postponed: Nop Scheduler: Nop pre-conditions: Id: - Valid Caller: - OtherTask State: - Active - Expired Postponed: all - enabled-by: true post-conditions: NotInInactiveState pre-conditions: Id: all Caller: all State: - Inactive Postponed: - One - Several - enabled-by: true post-conditions: NeverInExpiredState pre-conditions: Id: all Caller: all State: - Expired Postponed: - Zero type: requirement