diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-08 09:21:32 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2021-09-08 13:47:51 +0200 |
commit | 338ff25ef792972cae017a15fad61fc4534cebb5 (patch) | |
tree | c334b84727fc332ed35fdc8ddd17dfb42cc3b571 | |
parent | spec: Specify bad sticky thread queue enqueue (diff) | |
download | rtems-central-338ff25ef792972cae017a15fad61fc4534cebb5.tar.bz2 |
spec: Specify MrsP special case
-rw-r--r-- | spec/rtems/sem/req/mrsp-prio-change-while-waiting.yml | 29 | ||||
-rw-r--r-- | spec/rtems/sem/val/smp.yml | 218 |
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 |