summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-08 09:21:32 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2021-09-08 13:47:51 +0200
commit338ff25ef792972cae017a15fad61fc4534cebb5 (patch)
treec334b84727fc332ed35fdc8ddd17dfb42cc3b571
parentspec: Specify bad sticky thread queue enqueue (diff)
downloadrtems-central-338ff25ef792972cae017a15fad61fc4534cebb5.tar.bz2
spec: Specify MrsP special case
-rw-r--r--spec/rtems/sem/req/mrsp-prio-change-while-waiting.yml29
-rw-r--r--spec/rtems/sem/val/smp.yml218
2 files changed, 247 insertions, 0 deletions
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 00000000..abf6b247
--- /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 a23f8500..68e51ab1 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