[rtems-central commit] spec: Specify MrsP special case

Sebastian Huber sebh at rtems.org
Wed Sep 8 11:49:44 UTC 2021


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

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Wed Sep  8 09:21:32 2021 +0200

spec: Specify MrsP special case

---

 .../sem/req/mrsp-prio-change-while-waiting.yml     |  29 +++
 spec/rtems/sem/val/smp.yml                         | 218 +++++++++++++++++++++
 2 files changed, 247 insertions(+)

diff --git a/spec/rtems/sem/req/mrsp-prio-change-while-waiting.yml b/spec/rtems/sem/req/mrsp-prio-change-while-waiting.yml
new file mode 100644
index 0000000..abf6b24
--- /dev/null
+++ b/spec/rtems/sem/req/mrsp-prio-change-while-waiting.yml
@@ -0,0 +1,29 @@
+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: RTEMS_SMP
+links:
+- role: requirement-refinement
+  uid: ../if/group
+functional-type: function
+rationale: |
+  While a thread has a higher ${/glossary/priority-current:/term} than the
+  ceiling priority of a MrsP semaphore, while the semaphore has an owner
+  thread, if the thread tries to obtain the semaphore, then an error status is
+  returned to notify about a priority ceiling violation.  This error condition
+  is not checked if the ${/glossary/priority-current:/term} is raised to a
+  higher priority than the ceiling priority while the thread is enqueued on the
+  thread queue of the semaphore.  It would complicate the implementation
+  considerable to check this error condition and restore the thread state so
+  that an error status can be returned.  The error check before the thread is
+  enqueued helps to detect application design issues.  For the implementation
+  it does not matter if the ${/glossary/priority-current:/term} is higher than
+  a ceiling priority.
+references: []
+requirement-type: functional
+text: |
+  While a thread is waiting to obtain a MrsP semaphore, while its
+  ${/glossary/priority-current:/term} changed so that it is higher than the
+  ceiling priority of the semaphore, the thread is allowed to become the new
+  owner of the semaphore.
+type: requirement
diff --git a/spec/rtems/sem/val/smp.yml b/spec/rtems/sem/val/smp.yml
index a23f850..68e51ab 100644
--- a/spec/rtems/sem/val/smp.yml
+++ b/spec/rtems/sem/val/smp.yml
@@ -45,6 +45,188 @@ test-actions:
   links:
   - role: validation
     uid: /score/tq/req/fatal-enqueue-sticky-from-bad-state
+- action-brief: |
+    Create two worker threads, a MrsP mutex, and a priority inheritance mutex.
+    Use the mutexes and the workers to raise the
+    ${/glossary/priority-current:/term} to a higher priority than the ceiling
+    priority of the mutex while one of the workers waits on the mutex.
+  action-code: |
+    rtems_status_code   sc;
+    rtems_id            worker_id;
+    rtems_id            worker_2_id;
+    rtems_id            scheduler_b_id;
+    rtems_task_priority prio;
+
+    sc = rtems_scheduler_ident( TEST_SCHEDULER_B_NAME, &scheduler_b_id );
+    T_rsc_success( sc );
+
+    sc = rtems_semaphore_create(
+      rtems_build_name( 'M', 'U', 'T', 'X' ),
+      1,
+      RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY |
+        RTEMS_MULTIPROCESSOR_RESOURCE_SHARING,
+      PRIO_HIGH,
+      &ctx->mutex_id
+    );
+    T_rsc_success( sc );
+
+    sc = rtems_semaphore_set_priority(
+      ctx->mutex_id,
+      scheduler_b_id,
+      PRIO_HIGH,
+      &prio
+    );
+    T_rsc_success( sc );
+
+    ctx->mutex_2_id = CreateMutex();
+
+    worker_id = CreateTask( "WORK", PRIO_NORMAL );
+    SetScheduler( worker_id, scheduler_b_id, PRIO_NORMAL );
+
+    worker_2_id = CreateTask( "WRK2", PRIO_NORMAL );
+    SetScheduler( worker_2_id, scheduler_b_id, PRIO_VERY_HIGH );
+  checks:
+  - brief: |
+      Let the first worker try to obtain the MrsP mutex.  Check that it
+      acquired the ceiling priority.
+    code: |
+      ObtainMutex( ctx->mutex_id );
+      ctx->done = false;
+      StartTask( worker_id, ObtainReleaseMrsPTask, ctx );
+
+      while ( !ctx->done ) {
+        /* Wait */
+      }
+
+      ctx->done = false;
+      WaitForIntendToBlock( worker_id );
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_HIGH );
+    links: []
+  - brief: |
+      Let the second worker try to obtain the priority inheritance mutex.
+      Check that the first worker inherited the priority from the second
+      worker.
+    code: |
+      ctx->done_2 = false;
+      StartTask( worker_2_id, ObtainRelease2Task, ctx );
+
+      while ( !ctx->done_2 ) {
+        /* Wait */
+      }
+
+      ctx->done_2 = false;
+      WaitForExecutionStop( worker_2_id );
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_VERY_HIGH );
+    links: []
+  - brief: |
+      Set the ${/glossary/priority-real:/term} of the first worker.  Check that
+      it defines the ${/glossary/priority-current:/term}.
+    code: |
+      SetPriority( worker_id, PRIO_ULTRA_HIGH );
+
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_ULTRA_HIGH );
+    links: []
+  - brief: |
+      Release the MrsP mutex so that the first worker can to obtain it.  It
+      will replace a temporary priority node which is the maximum priority
+      node.  This is the first scenario we want to test.
+    code: |
+      ReleaseMutex( ctx->mutex_id );
+
+      while ( !ctx->done || !ctx->done_2 ) {
+        /* Wait */
+      }
+
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_ULTRA_HIGH );
+    links: []
+  - brief: |
+      Obtain the MrsP mutex for the runner thread to start the second scenario
+      we would like to test.
+    code: |
+      ObtainMutex( ctx->mutex_id );
+    links: []
+  - brief: |
+      Let the first worker try to obtain the MrsP mutex.  Check that it
+      acquired the ceiling priority.
+    code: |
+      ctx->done = false;
+      sc = rtems_task_restart( worker_id, (rtems_task_argument) ctx );
+      T_rsc_success( sc );
+
+      while ( !ctx->done ) {
+        /* Wait */
+      }
+
+      ctx->done = false;
+      WaitForIntendToBlock( worker_id );
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_HIGH );
+    links: []
+  - brief: |
+      Let the second worker try to obtain the priority inheritance mutex.
+      Check that the first worker inherited the priority from the second
+      worker.
+    code: |
+      ctx->done_2 = false;
+      sc = rtems_task_restart( worker_2_id, (rtems_task_argument) ctx );
+      T_rsc_success( sc );
+
+      while ( !ctx->done_2 ) {
+        /* Wait */
+      }
+
+      ctx->done_2 = false;
+      WaitForExecutionStop( worker_2_id );
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_VERY_HIGH );
+    links: []
+  - brief: |
+      Lower the priority of the second worker.  Check that the inherited
+      priority of the first worker reflects this priority change.
+    code: |
+      SetPriority( worker_2_id, PRIO_LOW );
+
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_HIGH );
+    links: []
+  - brief: |
+      Change the ${/glossary/priority-real:/term} of the first worker so that
+      it defines its ${/glossary/priority-current:/term}.
+    code: |
+      SetPriority( worker_id, PRIO_ULTRA_HIGH );
+
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_ULTRA_HIGH );
+    links: []
+  - brief: |
+      Release the MrsP mutex so that the first worker can to obtain it.  It
+      will replace a temporary priority node which is between the minimum and
+      maximum priority node.  This is the second scenario we want to test.
+    code: |
+      ReleaseMutex( ctx->mutex_id );
+
+      while ( !ctx->done || !ctx->done_2 ) {
+        /* Wait */
+      }
+
+      prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
+      T_eq_u32( prio, PRIO_ULTRA_HIGH );
+    links:
+    - role: validation
+      uid: ../req/mrsp-prio-change-while-waiting
+  - brief: |
+      Clean up all used resources.
+    code: |
+      DeleteTask( worker_id );
+      DeleteTask( worker_2_id );
+      DeleteMutex( ctx->mutex_id );
+      DeleteMutex( ctx->mutex_2_id );
+    links: []
+  links: []
 test-brief: |
   Tests SMP-specific semaphore behaviour.
 test-context:
@@ -54,10 +236,20 @@ test-context:
   member: |
     rtems_id mutex_id;
 - brief: |
+    This member contains the second mutex identifier.
+  description: null
+  member: |
+    rtems_id mutex_2_id;
+- brief: |
     If this member is true, then the worker is done.
   description: null
   member: |
     volatile bool done
+- brief: |
+    If this member is true, then the second worker is done.
+  description: null
+  member: |
+    volatile bool done_2
 test-context-support: null
 test-description: null
 test-header: null
@@ -111,6 +303,32 @@ test-support: |
     (void) _Thread_Dispatch_disable();
     ObtainMutex( ctx->mutex_id );
   }
+
+  static void ObtainReleaseMrsPTask( rtems_task_argument arg )
+  {
+    Context *ctx;
+
+    ctx = (Context *) arg;
+    ObtainMutex( ctx->mutex_2_id );
+    ctx->done = true;
+    ObtainMutex( ctx->mutex_id );
+    ReleaseMutex( ctx->mutex_id );
+    ReleaseMutex( ctx->mutex_2_id );
+    ctx->done = true;
+    SuspendSelf();
+  }
+
+  static void ObtainRelease2Task( rtems_task_argument arg )
+  {
+    Context *ctx;
+
+    ctx = (Context *) arg;
+    ctx->done_2 = true;
+    ObtainMutex( ctx->mutex_2_id );
+    ReleaseMutex( ctx->mutex_2_id );
+    ctx->done_2 = true;
+    SuspendSelf();
+  }
 test-target: testsuites/validation/tc-sem-smp.c
 test-teardown:
   brief: null



More information about the vc mailing list