From b71014376cedbe70f329324035af9ee86c569ae6 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 8 Sep 2021 13:35:02 +0200 Subject: valiation: Test MrsP special case --- testsuites/validation/tc-sem-smp.c | 266 ++++++++++++++++++++++++++++++++++++- 1 file changed, 262 insertions(+), 4 deletions(-) diff --git a/testsuites/validation/tc-sem-smp.c b/testsuites/validation/tc-sem-smp.c index 24ced13333..29593115e7 100644 --- a/testsuites/validation/tc-sem-smp.c +++ b/testsuites/validation/tc-sem-smp.c @@ -53,7 +53,6 @@ #endif #include -#include #include #include "ts-config.h" @@ -70,9 +69,50 @@ * * This test case performs the following actions: * - * - Create a worker thread and a mutex. Use the mutex and the worker to + * - Create a worker thread and a MrsP mutex. Use the mutex and the worker to * perform a bad sticky thread queue enqueue. * + * - Create two worker threads, a MrsP mutex, and a priority inheritance mutex. + * Use the mutexes and the workers to raise the current priority to a higher + * priority than the ceiling priority of the mutex while one of the workers + * waits on the mutex. + * + * - Let the first worker try to obtain the MrsP mutex. Check that it + * acquired the ceiling priority. + * + * - Let the second worker try to obtain the priority inheritance mutex. + * Check that the first worker inherited the priority from the second + * worker. + * + * - Set the real priority of the first worker. Check that it defines the + * current priority. + * + * - 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. + * + * - Obtain the MrsP mutex for the runner thread to start the second scenario + * we would like to test. + * + * - Let the first worker try to obtain the MrsP mutex. Check that it + * acquired the ceiling priority. + * + * - Let the second worker try to obtain the priority inheritance mutex. + * Check that the first worker inherited the priority from the second + * worker. + * + * - Lower the priority of the second worker. Check that the inherited + * priority of the first worker reflects this priority change. + * + * - Change the real priority of the first worker so that it defines its + * current priority. + * + * - 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. + * + * - Clean up all used resources. + * * @{ */ @@ -85,10 +125,20 @@ typedef struct { */ rtems_id mutex_id;; + /** + * @brief This member contains the second mutex identifier. + */ + rtems_id mutex_2_id;; + /** * @brief If this member is true, then the worker is done. */ volatile bool done; + + /** + * @brief If this member is true, then the second worker is done. + */ + volatile bool done_2; } RtemsSemValSmp_Context; static RtemsSemValSmp_Context @@ -166,9 +216,35 @@ static void BadEnqueueTask( rtems_task_argument arg ) 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(); +} + /** - * @brief Create a worker thread and a mutex. Use the mutex and the worker to - * perform a bad sticky thread queue enqueue. + * @brief Create a worker thread and a MrsP mutex. Use the mutex and the + * worker to perform a bad sticky thread queue enqueue. */ static void RtemsSemValSmp_Action_0( RtemsSemValSmp_Context *ctx ) { @@ -189,6 +265,7 @@ static void RtemsSemValSmp_Action_0( RtemsSemValSmp_Context *ctx ) PRIO_HIGH, &ctx->mutex_id ); + T_rsc_success( sc ); worker_id = CreateTask( "WORK", PRIO_NORMAL ); SetScheduler( worker_id, scheduler_b_id, PRIO_NORMAL ); @@ -206,6 +283,186 @@ static void RtemsSemValSmp_Action_0( RtemsSemValSmp_Context *ctx ) DeleteMutex( ctx->mutex_id ); } +/** + * @brief Create two worker threads, a MrsP mutex, and a priority inheritance + * mutex. Use the mutexes and the workers to raise the current priority to a + * higher priority than the ceiling priority of the mutex while one of the + * workers waits on the mutex. + */ +static void RtemsSemValSmp_Action_1( RtemsSemValSmp_Context *ctx ) +{ + 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 ); + + /* + * Let the first worker try to obtain the MrsP mutex. Check that it acquired + * the ceiling priority. + */ + 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 ); + + /* + * Let the second worker try to obtain the priority inheritance mutex. Check + * that the first worker inherited the priority from the second worker. + */ + 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 ); + + /* + * Set the real priority of the first worker. Check that it defines the + * current priority. + */ + SetPriority( worker_id, PRIO_ULTRA_HIGH ); + + prio = GetPriorityByScheduler( worker_id, scheduler_b_id ); + T_eq_u32( prio, PRIO_ULTRA_HIGH ); + + /* + * 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. + */ + 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 ); + + /* + * Obtain the MrsP mutex for the runner thread to start the second scenario + * we would like to test. + */ + ObtainMutex( ctx->mutex_id ); + + /* + * Let the first worker try to obtain the MrsP mutex. Check that it acquired + * the ceiling priority. + */ + 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 ); + + /* + * Let the second worker try to obtain the priority inheritance mutex. Check + * that the first worker inherited the priority from the second worker. + */ + 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 ); + + /* + * Lower the priority of the second worker. Check that the inherited + * priority of the first worker reflects this priority change. + */ + SetPriority( worker_2_id, PRIO_LOW ); + + prio = GetPriorityByScheduler( worker_id, scheduler_b_id ); + T_eq_u32( prio, PRIO_HIGH ); + + /* + * Change the real priority of the first worker so that it defines its + * current priority. + */ + SetPriority( worker_id, PRIO_ULTRA_HIGH ); + + prio = GetPriorityByScheduler( worker_id, scheduler_b_id ); + T_eq_u32( prio, PRIO_ULTRA_HIGH ); + + /* + * 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. + */ + 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 ); + + /* + * Clean up all used resources. + */ + DeleteTask( worker_id ); + DeleteTask( worker_2_id ); + DeleteMutex( ctx->mutex_id ); + DeleteMutex( ctx->mutex_2_id ); +} + /** * @fn void T_case_body_RtemsSemValSmp( void ) */ @@ -216,6 +473,7 @@ T_TEST_CASE_FIXTURE( RtemsSemValSmp, &RtemsSemValSmp_Fixture ) ctx = T_fixture_context(); RtemsSemValSmp_Action_0( ctx ); + RtemsSemValSmp_Action_1( ctx ); } /** @} */ -- cgit v1.2.3