[rtems-central commit] spec: Specify semaphore obtain timeouts

Sebastian Huber sebh at rtems.org
Wed Sep 15 06:02:35 UTC 2021


Module:    rtems-central
Branch:    master
Commit:    c34a9301ab07430660f8857de867ebde195006d5
Changeset: http://git.rtems.org/rtems-central/commit/?id=c34a9301ab07430660f8857de867ebde195006d5

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Thu Sep  9 09:06:20 2021 +0200

spec: Specify semaphore obtain timeouts

---

 spec/rtems/sem/req/timeout.yml   | 184 +++++++++++++++++++++++
 spec/score/status/if/timeout.yml |  12 ++
 spec/score/tq/req/timeout.yml    | 306 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 502 insertions(+)

diff --git a/spec/rtems/sem/req/timeout.yml b/spec/rtems/sem/req/timeout.yml
new file mode 100644
index 0000000..57b32b0
--- /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 0000000..5bc1bfa
--- /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 0000000..7e26d5f
--- /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



More information about the vc mailing list