diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-09 09:06:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-14 14:32:42 +0200 |
commit | c34a9301ab07430660f8857de867ebde195006d5 (patch) | |
tree | e3963f6704938d67cd3de1d19ffe1ab63b50f0b1 | |
parent | transitionmap: Fix pre-condition summary (diff) | |
download | rtems-central-c34a9301ab07430660f8857de867ebde195006d5.tar.bz2 |
spec: Specify semaphore obtain timeouts
-rw-r--r-- | spec/rtems/sem/req/timeout.yml | 184 | ||||
-rw-r--r-- | spec/score/status/if/timeout.yml | 12 | ||||
-rw-r--r-- | spec/score/tq/req/timeout.yml | 306 |
3 files changed, 502 insertions, 0 deletions
diff --git a/spec/rtems/sem/req/timeout.yml b/spec/rtems/sem/req/timeout.yml new file mode 100644 index 00000000..57b32b07 --- /dev/null +++ b/spec/rtems/sem/req/timeout.yml @@ -0,0 +1,184 @@ +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/obtain +post-conditions: +- name: Action + states: + - name: Timeout + test-code: | + ${/score/tq/req/timeout:/test-run}( &ctx->tq_ctx ); + text: | + The semaphore obtain timeout actions shall be done as specified by + ${/score/tq/req/timeout}. + test-epilogue: null + test-prologue: null +pre-conditions: +- name: Class + states: + - name: Counting + test-code: | + ctx->attribute_set |= RTEMS_COUNTING_SEMAPHORE; + ctx->tq_ctx.enqueue_variant = TQ_ENQUEUE_BLOCKS; + text: | + While the semaphore object is a counting semaphore. + - name: Simple + test-code: | + ctx->attribute_set |= RTEMS_SIMPLE_BINARY_SEMAPHORE; + ctx->tq_ctx.enqueue_variant = TQ_ENQUEUE_BLOCKS; + text: | + While the semaphore object is a simple binary semaphore. + - name: Binary + test-code: | + ctx->attribute_set |= RTEMS_BINARY_SEMAPHORE; + ctx->tq_ctx.enqueue_variant = TQ_ENQUEUE_BLOCKS; + text: | + While the semaphore object is a binary semaphore. + - name: PrioCeiling + test-code: | + ctx->attribute_set |= RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY_CEILING; + ctx->tq_ctx.enqueue_variant = TQ_ENQUEUE_BLOCKS; + text: | + While the semaphore object is a priority ceiling semaphore. + - name: PrioInherit + test-code: | + ctx->attribute_set |= RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY; + ctx->tq_ctx.enqueue_variant = TQ_ENQUEUE_BLOCKS; + text: | + While the semaphore object is a priority inheritance semaphore. + - name: MrsP + test-code: | + ctx->attribute_set |= RTEMS_BINARY_SEMAPHORE | + RTEMS_MULTIPROCESSOR_RESOURCE_SHARING; + ctx->tq_ctx.enqueue_variant = TQ_ENQUEUE_STICKY; + text: | + While the semaphore object is a MrsP semaphore. + test-epilogue: null + test-prologue: null +- name: Discipline + states: + - name: FIFO + test-code: | + ctx->attribute_set |= RTEMS_FIFO; + ctx->tq_ctx.discipline = TQ_FIFO; + text: | + While the semaphore uses the FIFO task wait queue discipline. + - name: Priority + test-code: | + ctx->attribute_set |= RTEMS_PRIORITY; + ctx->tq_ctx.discipline = TQ_PRIORITY; + text: | + While the semaphore uses the priority task wait queue discipline. + test-epilogue: null + test-prologue: null +rationale: null +references: [] +requirement-type: functional +skip-reasons: + NeedsPriorityDiscipline: | + Binary semaphores with a locking protocol are required to use the priority + task wait queue discipline. + NoMrsP: | + Where the system is build with SMP support disabled, the MrsP locking + protocol is not available. +test-action: | + rtems_status_code sc; + + sc = rtems_semaphore_create( + OBJECT_NAME, + 1, + ctx->attribute_set, + PRIO_HIGH, + &ctx->tq_ctx.thread_queue_id + ); + T_rsc_success( sc ); +test-brief: null +test-cleanup: + if ( ctx->tq_ctx.thread_queue_id != 0 ) { + rtems_status_code sc; + + sc = rtems_semaphore_delete( ctx->tq_ctx.thread_queue_id ); + T_rsc_success( sc ); + } +test-context: +- brief: | + This member contains the thread queue test context. + description: null + member: | + TQContext tq_ctx; +- brief: | + This member specifies if the attribute set of the semaphore. + description: null + member: | + rtems_attribute attribute_set +test-context-support: null +test-description: null +test-header: null +test-includes: +- rtems.h +- string.h +test-local-includes: +- tr-tq-timeout.h +- tx-thread-queue.h +- tx-support.h +test-prepare: | + ctx->attribute_set = RTEMS_DEFAULT_ATTRIBUTES; + ctx->tq_ctx.thread_queue_id = 0; +test-setup: + brief: null + code: | + memset( ctx, 0, sizeof( *ctx ) ); + ctx->tq_ctx.wait = TQ_WAIT_TICKS; + ctx->tq_ctx.enqueue_prepare = TQEnqueuePrepareClassicSem; + ctx->tq_ctx.enqueue_done = TQSurrenderClassicSem; + ctx->tq_ctx.enqueue = TQEnqueueClassicSem; + ctx->tq_ctx.surrender = TQSurrenderClassicSem; + ctx->tq_ctx.convert_status = TQConvertStatusClassic; + TQInitialize( &ctx->tq_ctx ); + description: null +test-stop: null +test-support: null +test-target: testsuites/validation/tc-sem-timeout.c +test-teardown: + brief: null + code: | + TQDestroy( &ctx->tq_ctx ); + description: null +text: | + When a semaphore obtain timeout happens. +transition-map: +- enabled-by: true + post-conditions: + Action: Timeout + pre-conditions: + Class: all + Discipline: all +- enabled-by: true + post-conditions: NoMrsP + pre-conditions: + Class: + - MrsP + Discipline: + - Priority +- enabled-by: true + post-conditions: NeedsPriorityDiscipline + pre-conditions: + Class: + - PrioCeiling + - PrioInherit + - MrsP + Discipline: + - FIFO +- enabled-by: RTEMS_SMP + post-conditions: + Action: Timeout + pre-conditions: + Class: + - MrsP + Discipline: + - Priority +type: requirement diff --git a/spec/score/status/if/timeout.yml b/spec/score/status/if/timeout.yml new file mode 100644 index 00000000..5bc1bfa9 --- /dev/null +++ b/spec/score/status/if/timeout.yml @@ -0,0 +1,12 @@ +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 +index-entries: [] +interface-type: unspecified +links: +- role: interface-placement + uid: header +name: STATUS_TIMEOUT +references: {} +type: interface diff --git a/spec/score/tq/req/timeout.yml b/spec/score/tq/req/timeout.yml new file mode 100644 index 00000000..7e26d5fc --- /dev/null +++ b/spec/score/tq/req/timeout.yml @@ -0,0 +1,306 @@ +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: requirement-refinement + uid: ../if/group +post-conditions: +- name: Status + states: + - name: Ok + test-code: | + T_eq_int( + ctx->tq_ctx->status[ TQ_BLOCKER_A ], + TQConvertStatus( ctx->tq_ctx, STATUS_SUCCESSFUL ) + ); + text: | + The return status of the directive call shall be derived from + ${../../status/if/successful:/name}. + - name: Timeout + test-code: | + T_eq_int( + ctx->tq_ctx->status[ TQ_BLOCKER_A ], + TQConvertStatus( ctx->tq_ctx, STATUS_TIMEOUT ) + ); + text: | + The return status of the directive call shall be derived from + ${../../status/if/timeout:/name}. + test-epilogue: null + test-prologue: null +- name: Unblock + states: + - name: 'Yes' + test-code: | + T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_A ) ); + T_eq_ptr( GetUnblock( ctx, &i ), NULL ); + text: | + The thread of the timeout operation shall not be unblocked by the timeout + operation. + - name: 'No' + test-code: | + T_eq_ptr( GetUnblock( ctx, &i ), NULL ); + text: | + The thread of the timeout operation shall be unblocked by the timeout + operation. + test-epilogue: null + test-prologue: | + size_t i; + + i = 0; +pre-conditions: +- name: EnqueueVariant + states: + - name: Blocking + test-code: | + if ( ctx->tq_ctx->enqueue_variant != TQ_ENQUEUE_BLOCKS ) { + ${.:skip} + } + text: | + Where the thread queue enqueue operation is blocking. + - name: Sticky + test-code: | + if ( ctx->tq_ctx->enqueue_variant != TQ_ENQUEUE_STICKY ) { + ${.:skip} + } + text: | + Where the thread queue enqueue operation is sticky. + test-epilogue: null + test-prologue: null +- name: WaitState + states: + - name: Blocked + test-code: | + if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) { + T_unreachable(); + } else { + TQEnqueuePrepare( ctx->tq_ctx ); + TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE ); + Yield(); + Tick( ctx ); + TQEnqueueDone( ctx->tq_ctx ); + } + text: | + While the thread of the timeout operation is in the blocked wait state. + - name: IntendToBlock + test-code: | + TQEnqueuePrepare( ctx->tq_ctx ); + + if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) { + Per_CPU_Control *cpu; + + TQSendAndWaitForIntendToBlock( + ctx->tq_ctx, + TQ_BLOCKER_A, + TQ_EVENT_ENQUEUE + ); + cpu = _Thread_Get_CPU( ctx->tq_ctx->worker_tcb[ TQ_BLOCKER_A ] ); + + /* + * We have to make sure that the worker thread inserted its thread + * timer. Checking the intend to block wait state is not enough to + * ensure this. + */ + while ( cpu->thread_dispatch_disable_level != 0 ) { + /* Wait */ + } + + Tick( ctx ); + WaitForExecutionStop( ctx->tq_ctx->worker_id[ TQ_BLOCKER_A ] ); + } else { + T_scheduler_set_event_handler( SchedulerBlock, ctx ); + TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE ); + Yield(); + } + + TQEnqueueDone( ctx->tq_ctx ); + text: | + While the thread of the timeout operation is in the intend to block wait + state. + - name: ReadyAgain + test-code: | + TQEnqueuePrepare( ctx->tq_ctx ); + + if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) { + TQSendAndWaitForIntendToBlock( + ctx->tq_ctx, + TQ_BLOCKER_A, + TQ_EVENT_ENQUEUE | TQ_EVENT_TIMEOUT | TQ_EVENT_SURRENDER | + TQ_EVENT_SCHEDULER_RECORD_STOP + ); + TQSchedulerRecordStart( ctx->tq_ctx ); + TQEnqueueDone( ctx->tq_ctx ); + WaitForExecutionStop( ctx->tq_ctx->worker_id[ TQ_BLOCKER_A ] ); + } else { + TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE ); + Yield(); + T_scheduler_set_event_handler( SchedulerUnblock, ctx ); + TQEnqueueDone( ctx->tq_ctx ); + TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_SURRENDER ); + } + text: | + While the thread of the timeout operation is in the ready again wait + state. + test-epilogue: null + test-prologue: null +rationale: null +references: [] +requirement-type: functional +skip-reasons: + StickyHasNoBlocking: | + When a sticky thread queue enqueue operation is performed, the blocked wait + state cannot occur. +test-action: | + /* + * The action is performed by the ``WaitState`` pre-condition preparation. + */ +test-brief: null +test-cleanup: null +test-context: +- brief: | + This member contains the call within ISR request. + description: null + member: | + CallWithinISRRequest request; +test-context-support: null +test-description: null +test-header: + code: null + freestanding: false + includes: [] + local-includes: + - tx-thread-queue.h + run-params: + - description: | + is the thread queue test context. + dir: inout + name: tq_ctx + specifier: TQContext *${.:name} + target: testsuites/validation/tr-tq-timeout.h +test-includes: +- rtems/score/threadimpl.h +test-local-includes: +- tx-support.h +- tr-tq-timeout.h +test-prepare: null +test-setup: + brief: null + code: | + ctx->request.arg = ctx; + TQReset( ctx->tq_ctx ); + + if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) { + TQSetScheduler( + ctx->tq_ctx, + TQ_BLOCKER_A, + ctx->tq_ctx->other_scheduler_id, + PRIO_NORMAL + ); + } else { + TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_A, PRIO_HIGH ); + } + description: null +test-stop: null +test-support: | + typedef ${.:/test-context-type} Context; + + static const rtems_tcb *GetUnblock( Context *ctx, size_t *index ) + { + return TQGetNextUnblock( ctx->tq_ctx, index )->thread; + } + + static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker ) + { + return ctx->tq_ctx->worker_tcb[ worker ]; + } + + static void Tick( void *arg ) + { + Context *ctx; + + ctx = arg; + TQSchedulerRecordStart( ctx->tq_ctx ); + FinalClockTick(); + TQSchedulerRecordStop( ctx->tq_ctx ); + } + + static void SchedulerBlock( void *arg, const T_scheduler_event *event ) + { + Context *ctx; + + ctx = arg; + + if ( event->operation == T_SCHEDULER_BLOCK ) { + T_scheduler_set_event_handler( NULL, NULL ); + ctx->request.handler = Tick; + CallWithinISRSubmit( &ctx->request ); + } + } + + static void ThreadTimeout( void *arg ) + { + Context *ctx; + + ctx = arg; + TQSchedulerRecordStart( ctx->tq_ctx ); + _Thread_Timeout( + &ctx->tq_ctx->worker_tcb[ TQ_BLOCKER_A ]->Timer.Watchdog + ); + TQSchedulerRecordStop( ctx->tq_ctx ); + } + + static void SchedulerUnblock( void *arg, const T_scheduler_event *event ) + { + Context *ctx; + + ctx = arg; + + if ( event->operation == T_SCHEDULER_UNBLOCK ) { + T_scheduler_set_event_handler( NULL, NULL ); + ctx->request.handler = ThreadTimeout; + CallWithinISRSubmit( &ctx->request ); + } + } +test-target: testsuites/validation/tr-tq-timeout.c +test-teardown: + brief: null + code: | + TQReset( ctx->tq_ctx ); + description: null +text: | + When the thread queue enqueue operation timed out. +transition-map: +- enabled-by: true + post-conditions: + Status: Timeout + Unblock: 'Yes' + pre-conditions: + EnqueueVariant: + - Blocking + WaitState: + - Blocked +- enabled-by: true + post-conditions: + Status: Timeout + Unblock: 'No' + pre-conditions: + EnqueueVariant: all + WaitState: + - IntendToBlock +- enabled-by: true + post-conditions: + Status: Ok + Unblock: 'No' + pre-conditions: + EnqueueVariant: all + WaitState: + - ReadyAgain +- enabled-by: true + post-conditions: StickyHasNoBlocking + pre-conditions: + EnqueueVariant: + - Sticky + WaitState: + - Blocked +type: requirement |