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/mode post-conditions: - name: Status states: - name: Ok test-code: | T_rsc_success( ctx->status ); text: | The return status of ${../if/mode:/name} shall be ${../../status/if/successful:/name}. - name: InvAddr test-code: | T_rsc( ctx->status, RTEMS_INVALID_ADDRESS ); text: | The return status of ${../if/mode:/name} shall be ${../../status/if/invalid-address:/name}. - name: NotImplIntLvl test-code: | T_rsc( ctx->status, RTEMS_NOT_IMPLEMENTED ); text: | The return status of ${../if/mode:/name} shall be ${../../status/if/not-implemented:/name}. - name: NotImplIntLvlSMP test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { T_rsc( ctx->status, RTEMS_NOT_IMPLEMENTED ); } else { T_rsc_success( ctx->status ); } text: | Where the system needs inter-processor interrupts, the return status of ${../if/mode:/name} shall be ${../../status/if/not-implemented:/name}. Where the system does not need inter-processor interrupts, the return status of ${../if/mode:/name} shall be ${../../status/if/successful:/name}. - name: NotImplNoPreempt test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { T_rsc( ctx->status, RTEMS_NOT_IMPLEMENTED ); } else { T_rsc_success( ctx->status ); } text: | Where the scheduler does not support the no-preempt mode, the return status of ${../if/mode:/name} shall be ${../../status/if/not-implemented:/name}. Where the scheduler does support the no-preempt mode, the return status of ${../if/mode:/name} shall be ${../../status/if/successful:/name}. test-epilogue: null test-prologue: null - name: Preempt states: - name: 'Yes' test-code: | T_eq_u32( ctx->worker_counter_after, ctx->worker_counter_before + 1 ); text: | The calling task shall be preempted by a higher priority ready task during the ${../if/mode:/name} call. - name: 'No' test-code: | T_eq_u32( ctx->worker_counter_after, ctx->worker_counter_before ); text: | The calling task shall not be preempted during the ${../if/mode:/name} call. - name: Maybe test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { T_eq_u32( ctx->worker_counter_after, ctx->worker_counter_before ); } else { T_eq_u32( ctx->worker_counter_after, ctx->worker_counter_before + 1 ); } text: | Where the scheduler does not support the no-preempt mode, the calling task shall not be preempted during the ${../if/mode:/name} call. Where the scheduler does support the no-preempt mode, the calling task shall be preempted by a higher priority ready task during the ${../if/mode:/name} call. test-epilogue: null test-prologue: null - name: ASR states: - name: 'Yes' test-code: | T_eq_u32( ctx->signal_counter_after, ctx->signal_counter_before + 1 ); text: | The calling task shall process pending signals during the ${../if/mode:/name} call. - name: 'No' test-code: | T_eq_u32( ctx->signal_counter_after, ctx->signal_counter_before ); text: | The calling task shall not process signals during the ${../if/mode:/name} call. - name: Maybe test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { T_eq_u32( ctx->signal_counter_after, ctx->signal_counter_before ); } else { T_eq_u32( ctx->signal_counter_after, ctx->signal_counter_before + 1 ); } text: | Where the scheduler does not support the no-preempt mode, the calling task shall not process signals during the ${../if/mode:/name} call. Where the scheduler does support the no-preempt mode, the calling task shall process pending signals during the ${../if/mode:/name} call. test-epilogue: null test-prologue: null - name: PMVar states: - name: Set test-code: | T_eq_ptr( ctx->previous_mode_set, &ctx->previous_mode_set_value ); T_eq_u32( ctx->previous_mode_set_value, ctx->current_mode ); text: | The value of the object referenced by the ${../if/mode:/params[2]/name} parameter shall be set to the task modes of the calling task on entry of the call to ${../if/mode:/name}. - name: Nop test-code: | T_eq_u32( ctx->previous_mode_set_value, INVALID_MODE ); text: | Objects referenced by the ${../if/create:/params[2]/name} parameter in past calls to ${../if/mode:/name} shall not be accessed by the ${../if/mode:/name} call. - name: Maybe test-code: | T_eq_ptr( ctx->previous_mode_set, &ctx->previous_mode_set_value ); if ( rtems_configuration_get_maximum_processors() > 1 ) { T_eq_u32( ctx->previous_mode_set_value, INVALID_MODE ); } else { T_eq_u32( ctx->previous_mode_set_value, ctx->current_mode ); } text: | Where the scheduler does not support the no-preempt mode, objects referenced by the ${../if/create:/params[2]/name} parameter in past calls to ${../if/mode:/name} shall not be accessed by the ${../if/mode:/name} call. Where the scheduler does support the no-preempt mode, the value of the object referenced by the ${../if/mode:/params[2]/name} parameter shall be set to the task modes of the calling task on entry of the call to ${../if/mode:/name}. test-epilogue: null test-prologue: null - name: Mode states: - name: Set test-code: | CheckMode( ctx, ctx->current_mode, ctx->mode_mask, ctx->mode_set ); text: | The task modes of the calling task indicated by the ${../if/mode:/params[1]/name} parameter shall be set to the corrsponding modes specified by the ${../if/mode:/params[0]/name} parameter. - name: Nop test-code: | CheckMode( ctx, ctx->current_mode, 0, 0 ); text: | The task modes of the calling task shall not be modified by the ${../if/mode:/name} call. - name: Maybe test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { CheckMode( ctx, ctx->current_mode, 0, 0 ); } else { CheckMode( ctx, ctx->current_mode, ctx->mode_mask, ctx->mode_set ); } text: | Where the scheduler does not support the no-preempt mode, the task modes of the calling task shall not be modified by the ${../if/mode:/name} call. Where the scheduler does support the no-preempt mode, the task modes of the calling task indicated by the ${../if/mode:/params[1]/name} parameter shall be set to the corrsponding modes specified by the ${../if/mode:/params[0]/name} parameter. test-epilogue: null test-prologue: null pre-conditions: - name: PrevMode states: - name: Valid test-code: | ctx->previous_mode_set = &ctx->previous_mode_set_value; text: | While the ${../if/mode:/params[2]/name} parameter references an object of type ${../../mode/if/mode:/name}. - name: 'Null' test-code: | ctx->previous_mode_set = NULL; text: | While the ${../if/mode:/params[2]/name} parameter is ${/c/if/null:/name}. test-epilogue: null test-prologue: null - name: PreemptCur states: - name: 'Yes' test-code: | ctx->current_mode |= RTEMS_PREEMPT; text: | While the calling task has preemption enabled. - name: 'No' test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { ctx->current_mode |= RTEMS_PREEMPT; } else { ctx->current_mode |= RTEMS_NO_PREEMPT; } text: | Where the scheduler does not support the no-preempt mode, while the calling task has preemption enabled. Where the scheduler does support the no-preempt mode, while the calling task has preemption disabled. test-epilogue: null test-prologue: null - name: TimesliceCur states: - name: 'Yes' test-code: | ctx->current_mode |= RTEMS_TIMESLICE; text: | While the calling task has timeslicing enabled. - name: 'No' test-code: | ctx->current_mode |= RTEMS_NO_TIMESLICE; text: | While the calling task has timeslicing disabled. test-epilogue: null test-prologue: null - name: ASRCur states: - name: 'Yes' test-code: | ctx->current_mode |= RTEMS_ASR; text: | While the calling task has ASR processing enabled. - name: 'No' test-code: | ctx->current_mode |= RTEMS_NO_ASR; text: | While the calling task has ASR processing disabled. test-epilogue: null test-prologue: null - name: IntLvlCur states: - name: Zero test-code: | ctx->current_mode |= RTEMS_INTERRUPT_LEVEL( 0 ); text: | While the calling task executes with an interrupt level of zero. - name: Positive test-code: | if ( rtems_configuration_get_maximum_processors() > 1 ) { ctx->current_mode |= RTEMS_INTERRUPT_LEVEL( 0 ); } else { ctx->current_mode |= RTEMS_INTERRUPT_LEVEL( 1 ); } text: | Where the system needs inter-processor interrupts, while the calling task executes with an interrupt level of zero. Where the system does not need inter-processor interrupts, while the calling task executes with an an interrupt level greater than zero and less than or equal to ${/score/cpu/if/modes-interrupt-mask:/name}. test-epilogue: null test-prologue: null - name: Preempt states: - name: 'Yes' test-code: | ctx->mode_set |= RTEMS_PREEMPT; text: | While the ${../if/mode:/params[0]/name} parameter specifies that preemption is enabled. - name: 'No' test-code: | ctx->mode_set |= RTEMS_NO_PREEMPT; text: | While the ${../if/mode:/params[0]/name} parameter specifies that preemption is disabled. test-epilogue: null test-prologue: null - name: Timeslice states: - name: 'Yes' test-code: | ctx->mode_set |= RTEMS_TIMESLICE; text: | While the ${../if/mode:/params[0]/name} parameter specifies that timeslicing is enabled. - name: 'No' test-code: | ctx->mode_set |= RTEMS_NO_TIMESLICE; text: | While the ${../if/mode:/params[0]/name} parameter specifies that timeslicing is disabled. test-epilogue: null test-prologue: null - name: ASR states: - name: 'Yes' test-code: | ctx->mode_set |= RTEMS_ASR; text: | While the ${../if/mode:/params[0]/name} parameter specifies that ASR processing is enabled. - name: 'No' test-code: | ctx->mode_set |= RTEMS_NO_ASR; text: | While the ${../if/mode:/params[0]/name} parameter specifies that ASR processing is disabled. test-epilogue: null test-prologue: null - name: IntLvl states: - name: Zero test-code: | ctx->mode_set |= RTEMS_INTERRUPT_LEVEL( 0 ); text: | While the ${../if/mode:/params[0]/name} parameter specifies an interrupt level of zero. - name: Positive test-code: | ctx->mode_set |= RTEMS_INTERRUPT_LEVEL( 1 ); text: | While the ${../if/mode:/params[0]/name} parameter specifies an interrupt level greater than zero and less than or equal to ${/score/cpu/if/modes-interrupt-mask:/name}. test-epilogue: null test-prologue: null - name: PreemptMsk states: - name: 'Yes' test-code: | ctx->mode_mask |= RTEMS_PREEMPT_MASK; text: | While the ${../if/mode:/params[1]/name} parameter specifies that the preemption mode shall be set. - name: 'No' test-code: | /* This is the default mode mask */ text: | While the ${../if/mode:/params[1]/name} parameter specifies that the preemption mode shall not be set. test-epilogue: null test-prologue: null - name: TimesliceMsk states: - name: 'Yes' test-code: | ctx->mode_mask |= RTEMS_TIMESLICE_MASK; text: | While the ${../if/mode:/params[1]/name} parameter specifies that the timeslicing mode shall be set. - name: 'No' test-code: | /* This is the default mode mask */ text: | While the ${../if/mode:/params[1]/name} parameter specifies that the timeslicing mode shall not be set. test-epilogue: null test-prologue: null - name: ASRMsk states: - name: 'Yes' test-code: | ctx->mode_mask |= RTEMS_ASR_MASK; text: | While the ${../if/mode:/params[1]/name} parameter specifies that the ASR processing mode shall be set. - name: 'No' test-code: | /* This is the default mode mask */ text: | While the ${../if/mode:/params[1]/name} parameter specifies that the ASR processing mode shall not be set. test-epilogue: null test-prologue: null - name: IntLvlMsk states: - name: 'Yes' test-code: | ctx->mode_mask |= RTEMS_INTERRUPT_MASK; text: | While the ${../if/mode:/params[1]/name} parameter specifies that the interrupt level shall be set. - name: 'No' test-code: | /* This is the default mode mask */ text: | While the ${../if/mode:/params[1]/name} parameter specifies that the interrupt level shall not be set. test-epilogue: null test-prologue: null rationale: null references: [] requirement-type: functional skip-reasons: RobustThreadDispatching: | Where the system enabled robust thread dispatching, the interrupt level mode of a task shall be exactly zero. test-action: | rtems_status_code sc; rtems_mode mode; sc = rtems_task_mode( ctx->current_mode, RTEMS_ALL_MODE_MASKS, &mode ); T_rsc_success( sc ); SendEvents( ctx->worker_id, EVENT_MAKE_READY ); sc = rtems_signal_catch( SignalHandler, ctx->current_mode | RTEMS_NO_ASR ); T_rsc_success( sc ); sc = rtems_signal_send( RTEMS_SELF, 0xdeadbeef ); T_rsc_success( sc ); ctx->worker_counter_before = ctx->worker_counter; ctx->signal_counter_before = ctx->signal_counter; ctx->status = rtems_task_mode( ctx->mode_set, ctx->mode_mask, ctx->previous_mode_set ); ctx->worker_counter_after = ctx->worker_counter; ctx->signal_counter_after = ctx->signal_counter; test-brief: null test-cleanup: | rtems_status_code sc; rtems_mode mode; sc = rtems_task_mode( RTEMS_DEFAULT_MODES, RTEMS_ALL_MODE_MASKS, &mode ); T_rsc_success( sc ); sc = rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ); T_rsc_success( sc ); sc = rtems_signal_catch( NULL, RTEMS_DEFAULT_MODES ); T_rsc_success( sc ); test-context: - brief: | This member contains the object identifier of the worker task. description: null member: | rtems_id worker_id - brief: null If this member is contains the initial mode of the runner. description: null member: | rtems_mode runner_mode - brief: | This member provides a value for the previous mode set. description: null member: | rtems_mode previous_mode_set_value - brief: | This member specifies the task mode in which rtems_task_mode() is called. description: null member: | rtems_mode current_mode - brief: | This member counts worker activity. description: null member: | uint32_t worker_counter - brief: | This member contains worker counter before the rtems_task_mode() call. description: null member: | uint32_t worker_counter_before - brief: | This member contains worker counter after the rtems_task_mode() call. description: null member: | uint32_t worker_counter_after - brief: | This member counts signal handler activity. description: null member: | uint32_t signal_counter - brief: | This member contains signal counter before the rtems_task_mode() call. description: null member: | uint32_t signal_counter_before - brief: | This member contains signal counter after the rtems_task_mode() call. description: null member: | uint32_t signal_counter_after - brief: | This member specifies the ${../if/mode:/params[0]/name} parameter for rtems_task_mode(). description: null member: | rtems_mode mode_set - brief: | This member specifies the mode mask ${../if/mode:/params[1]/name} parameter for rtems_task_mode() for the action. description: null member: | rtems_mode mode_mask - brief: | This member specifies the previous mode set ${../if/mode:/params[2]/name} parameter for rtems_task_mode(). description: null member: | rtems_mode *previous_mode_set - brief: | This member contains the return status of the rtems_task_mode() call. description: null member: | rtems_status_code status test-context-support: null test-description: null test-header: null test-includes: - rtems.h - string.h test-local-includes: - tx-support.h test-prepare: | ctx->current_mode = RTEMS_DEFAULT_MODES; ctx->mode_set = RTEMS_DEFAULT_MODES; ctx->mode_mask = RTEMS_CURRENT_MODE; ctx->previous_mode_set_value = INVALID_MODE; test-setup: brief: null code: | rtems_status_code sc; memset( ctx, 0, sizeof( *ctx ) ); sc = rtems_task_mode( RTEMS_DEFAULT_MODES, RTEMS_CURRENT_MODE, &ctx->runner_mode ); T_rsc_success( sc ); SetSelfPriority( PRIO_NORMAL ); ctx->worker_id = CreateTask( "WORK", PRIO_HIGH ); StartTask( ctx->worker_id, Worker, ctx ); description: null test-stop: null test-support: | #define INVALID_MODE 0xffffffff #define EVENT_MAKE_READY RTEMS_EVENT_0 #define EVENT_TIMESLICE RTEMS_EVENT_1 typedef RtemsTaskReqMode_Context Context; static void Worker( rtems_task_argument arg ) { Context *ctx; ctx = (Context *) arg; while ( true ) { rtems_event_set events; events = ReceiveAnyEvents(); if ( ( events & EVENT_TIMESLICE ) != 0 ) { SetSelfPriority( PRIO_NORMAL ); SetSelfPriority( PRIO_HIGH ); } ++ctx->worker_counter; } } static void SignalHandler( rtems_signal_set signal_set ) { Context *ctx; ctx = T_fixture_context(); ++ctx->signal_counter; T_eq_u32( signal_set, 0xdeadbeef ); } static void ExhaustTimeslice( void ) { uint32_t ticks; for ( ticks = 0; ticks < rtems_configuration_get_ticks_per_timeslice(); ++ticks ) { ClockTick(); } } static void CheckMode( Context *ctx, rtems_mode mode, rtems_mode mask, rtems_mode set ) { rtems_status_code sc; uint32_t counter; mode &= ~mask; mode |= set & mask; counter = ctx->worker_counter; SendEvents( ctx->worker_id, EVENT_MAKE_READY ); if ( ( mode & RTEMS_PREEMPT_MASK ) == RTEMS_PREEMPT ) { T_eq_u32( ctx->worker_counter, counter + 1 ); } else { T_eq_u32( ctx->worker_counter, counter ); } counter = ctx->worker_counter; SendEvents( ctx->worker_id, EVENT_TIMESLICE ); ExhaustTimeslice(); if ( ( mode & RTEMS_PREEMPT_MASK ) == RTEMS_PREEMPT ) { if ( ( mode & RTEMS_TIMESLICE_MASK ) == RTEMS_TIMESLICE ) { T_eq_u32( ctx->worker_counter, counter + 1 ); } else { T_eq_u32( ctx->worker_counter, counter ); } } else { T_eq_u32( ctx->worker_counter, counter ); } counter = ctx->signal_counter; sc = rtems_signal_send( RTEMS_SELF, 0xdeadbeef ); T_rsc_success( sc ); if ( ( mode & RTEMS_ASR_MASK ) == RTEMS_ASR ) { T_eq_u32( ctx->signal_counter, counter + 1 ); } else { T_eq_u32( ctx->signal_counter, counter ); } T_eq_u32( mode & RTEMS_INTERRUPT_MASK, _ISR_Get_level() ); } test-target: testsuites/validation/tc-task-mode.c test-teardown: brief: null code: | DeleteTask( ctx->worker_id ); RestoreRunnerMode(); RestoreRunnerPriority(); description: null text: ${.:text-template} transition-map: - enabled-by: true post-conditions: Status: - if: pre-conditions: PrevMode: 'Null' then: InvAddr - else: Ok Preempt: - if: and: - post-conditions: Status: Ok - pre-conditions: PreemptCur: 'No' Preempt: 'Yes' PreemptMsk: 'Yes' then: 'Yes' - else: 'No' ASR: - if: and: - post-conditions: Status: Ok - pre-conditions: ASRCur: 'No' ASR: 'Yes' ASRMsk: 'Yes' then: 'Yes' - else: 'No' PMVar: - if: pre-conditions: PrevMode: 'Null' then: Nop - else: Set Mode: - if: pre-conditions: PrevMode: 'Null' then: Nop - else: Set pre-conditions: PreemptCur: all TimesliceCur: all ASRCur: all IntLvlCur: all Preempt: all Timeslice: all ASR: all IntLvl: all PreemptMsk: all TimesliceMsk: all ASRMsk: all IntLvlMsk: all PrevMode: all - enabled-by: CPU_ENABLE_ROBUST_THREAD_DISPATCH post-conditions: Status: NotImplIntLvl Preempt: 'No' ASR: 'No' PMVar: Nop Mode: Nop pre-conditions: PreemptCur: all TimesliceCur: all ASRCur: all IntLvlCur: - Zero Preempt: all Timeslice: all ASR: all IntLvl: - Positive PreemptMsk: all TimesliceMsk: all ASRMsk: all IntLvlMsk: - 'Yes' PrevMode: - Valid - enabled-by: CPU_ENABLE_ROBUST_THREAD_DISPATCH post-conditions: RobustThreadDispatching pre-conditions: PreemptCur: all TimesliceCur: all ASRCur: all IntLvlCur: - Positive Preempt: all Timeslice: all ASR: all IntLvl: all PreemptMsk: all TimesliceMsk: all ASRMsk: all IntLvlMsk: all PrevMode: all - enabled-by: RTEMS_SMP post-conditions: Status: - if: pre-conditions: Preempt: 'No' PreemptMsk: 'Yes' then: NotImplNoPreempt - if: pre-conditions: IntLvl: Positive IntLvlMsk: 'Yes' then: NotImplIntLvlSMP - else: Ok Preempt: - if: pre-conditions: PreemptCur: 'No' Preempt: 'Yes' PreemptMsk: 'Yes' then: Maybe - else: 'No' ASR: - if: and: - pre-conditions: ASRCur: 'No' ASR: 'Yes' ASRMsk: 'Yes' - or: - pre-conditions: Preempt: 'No' PreemptMsk: 'Yes' - pre-conditions: IntLvl: Positive IntLvlMsk: 'Yes' then: Maybe - if: and: - pre-conditions: ASRCur: 'No' ASR: 'Yes' ASRMsk: 'Yes' - or: - pre-conditions: PreemptMsk: 'No' IntLvlMsk: 'No' - pre-conditions: Preempt: 'Yes' IntLvlMsk: 'No' - pre-conditions: PreemptMsk: 'No' IntLvl: Zero - pre-conditions: Preempt: 'Yes' IntLvl: Zero then: 'Yes' - else: 'No' PMVar: - if: - pre-conditions: Preempt: 'No' PreemptMsk: 'Yes' - pre-conditions: IntLvl: Positive IntLvlMsk: 'Yes' then: Maybe - else: Set Mode: - if: - pre-conditions: Preempt: 'No' PreemptMsk: 'Yes' - pre-conditions: IntLvl: Positive IntLvlMsk: 'Yes' then: Maybe - else: Set pre-conditions: PreemptCur: all TimesliceCur: all ASRCur: all IntLvlCur: all Preempt: all Timeslice: all ASR: all IntLvl: all PreemptMsk: all TimesliceMsk: all ASRMsk: all IntLvlMsk: all PrevMode: - Valid type: requirement