summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-09 09:06:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-14 14:32:42 +0200
commitc34a9301ab07430660f8857de867ebde195006d5 (patch)
treee3963f6704938d67cd3de1d19ffe1ab63b50f0b1
parenttransitionmap: Fix pre-condition summary (diff)
downloadrtems-central-c34a9301ab07430660f8857de867ebde195006d5.tar.bz2
spec: Specify semaphore obtain timeouts
-rw-r--r--spec/rtems/sem/req/timeout.yml184
-rw-r--r--spec/score/status/if/timeout.yml12
-rw-r--r--spec/score/tq/req/timeout.yml306
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