From af90f783f0d69b9f9ad1d714e8d40ae821d16c29 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 5 Jul 2022 08:22:58 +0200 Subject: validation: Test scheduler detail This particular state during a reconsider help request scheduler operation was only covered by the existing test suites under some timing conditions. Update #3716. --- testsuites/validation/tc-sched-smp.c | 137 ++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/testsuites/validation/tc-sched-smp.c b/testsuites/validation/tc-sched-smp.c index 957a978980..6eb98b5360 100644 --- a/testsuites/validation/tc-sched-smp.c +++ b/testsuites/validation/tc-sched-smp.c @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2021 embedded brains GmbH (http://www.embedded-brains.de) + * Copyright (C) 2021, 2022 embedded brains GmbH (http://www.embedded-brains.de) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -55,6 +55,7 @@ #include #include #include +#include #include #include "tx-support.h" @@ -213,6 +214,24 @@ * * - Clean up all used resources. * + * - Create three worker threads and a mutex. Use the mutex and the worker to + * check that a not scheduled thread does not get removed from the set of + * ready threads of a scheduler when a help request is reconsidered. + * + * - Prevent that worker B can perform a post-switch cleanup. + * + * - Give worker C a lower priority than worker B. Worker B will try to + * finish the thread dispatch by doing a post-switch cleanup. The + * post-switch cleanup cannot progress since the runner owns the thread + * state lock. Wait until the other processor waits on the thread state + * lock of worker B. + * + * - Give worker C a higher priority than worker B. Let worker B do its + * post-switch cleanup which will carry out the reconsider help requests + * for a not scheduled thread. + * + * - Clean up all used resources. + * * @{ */ @@ -250,7 +269,17 @@ typedef struct { /** * @brief This member contains the worker busy status. */ - volatile bool busy[ WORKER_COUNT ];; + volatile bool busy[ WORKER_COUNT ]; + + /** + * @brief This member contains an ISR lock context. + */ + ISR_lock_Context lock_context; + + /** + * @brief This member contains a counter. + */ + uint32_t counter; /** * @brief If this member is true, then the worker shall be in the busy loop. @@ -686,6 +715,51 @@ static void CleanupOwnerBlocked( Context *ctx ) SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_A_ID, PRIO_HIGH ); } +static void ReconsiderHelpRequestB( + void *arg, + const T_scheduler_event *event, + T_scheduler_when when +) +{ + Context *ctx; + + (void) when; + ctx = arg; + + if ( event->operation == T_SCHEDULER_RECONSIDER_HELP_REQUEST ) { + Scheduler_SMP_Node *node; + + node = (Scheduler_SMP_Node *) event->node; + T_eq_int( node->state, SCHEDULER_SMP_NODE_READY ); + ++ctx->counter; + } +} + +static void ReleaseThreadLockB( + void *arg, + const T_scheduler_event *event, + T_scheduler_when when +) +{ + Context *ctx; + + ctx = arg; + + if ( + when == T_SCHEDULER_AFTER && + event->operation == T_SCHEDULER_UPDATE_PRIORITY + ) { + Thread_Control *worker_b; + + T_scheduler_set_event_handler( ReconsiderHelpRequestB, ctx ); + + worker_b = GetThread( ctx->worker_id[ WORKER_B ] ); + T_eq_int( worker_b->Scheduler.state, THREAD_SCHEDULER_READY ); + + _Thread_State_release_critical( worker_b, &ctx->lock_context ); + } +} + static void Worker( rtems_task_argument arg, WorkerIndex worker ) { Context *ctx; @@ -1232,6 +1306,64 @@ static void ScoreSchedSmpValSmp_Action_16( ScoreSchedSmpValSmp_Context *ctx ) CleanupOwnerBlocked( ctx ); } +/** + * @brief Create three worker threads and a mutex. Use the mutex and the + * worker to check that a not scheduled thread does not get removed from the + * set of ready threads of a scheduler when a help request is reconsidered. + */ +static void ScoreSchedSmpValSmp_Action_17( ScoreSchedSmpValSmp_Context *ctx ) +{ + Thread_Control *worker_b; + + SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_B_ID, PRIO_NORMAL ); + SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_B_ID, PRIO_HIGH ); + SendAndSync( ctx, WORKER_B, EVENT_OBTAIN ); + SendEvents( ctx->worker_id[ WORKER_A ], EVENT_OBTAIN ); + SetPriority( ctx->worker_id[ WORKER_A ], PRIO_LOW ); + MakeBusy( ctx, WORKER_B ); + WaitForBusy( ctx, WORKER_B ); + MakeBusy( ctx, WORKER_C ); + WaitForBusy( ctx, WORKER_C ); + + /* + * Prevent that worker B can perform a post-switch cleanup. + */ + worker_b = GetThread( ctx->worker_id[ WORKER_B ] ); + _Thread_State_acquire( worker_b, &ctx->lock_context ); + _ISR_lock_ISR_enable( &ctx->lock_context ); + + /* + * Give worker C a lower priority than worker B. Worker B will try to finish + * the thread dispatch by doing a post-switch cleanup. The post-switch + * cleanup cannot progress since the runner owns the thread state lock. Wait + * until the other processor waits on the thread state lock of worker B. + */ + SetPriority( ctx->worker_id[ WORKER_C ], PRIO_LOW ); + TicketLockWaitForOthers( &worker_b->Join_queue.Queue.Lock, 1 ); + + /* + * Give worker C a higher priority than worker B. Let worker B do its + * post-switch cleanup which will carry out the reconsider help requests for + * a not scheduled thread. + */ + ctx->counter = 0; + T_scheduler_set_event_handler( ReleaseThreadLockB, ctx ); + SetPriority( ctx->worker_id[ WORKER_C ], PRIO_HIGH ); + T_scheduler_set_event_handler( NULL, NULL ); + T_eq_u32( ctx->counter, 4 ); + + /* + * Clean up all used resources. + */ + StopBusy( ctx, WORKER_B ); + StopBusy( ctx, WORKER_C ); + SendAndSync( ctx, WORKER_B, EVENT_RELEASE ); + SetPriority( ctx->worker_id[ WORKER_A ], PRIO_HIGH ); + SendEvents( ctx->worker_id[ WORKER_A ], EVENT_RELEASE ); + SetScheduler( ctx->worker_id[ WORKER_B ], SCHEDULER_A_ID, PRIO_HIGH ); + SetScheduler( ctx->worker_id[ WORKER_C ], SCHEDULER_A_ID, PRIO_HIGH ); +} + /** * @fn void T_case_body_ScoreSchedSmpValSmp( void ) */ @@ -1258,6 +1390,7 @@ T_TEST_CASE_FIXTURE( ScoreSchedSmpValSmp, &ScoreSchedSmpValSmp_Fixture ) ScoreSchedSmpValSmp_Action_14( ctx ); ScoreSchedSmpValSmp_Action_15( ctx ); ScoreSchedSmpValSmp_Action_16( ctx ); + ScoreSchedSmpValSmp_Action_17( ctx ); } /** @} */ -- cgit v1.2.3