/* SPDX-License-Identifier: BSD-2-Clause */ /** * @file * * @ingroup RTEMSTestCaseScoreSchedSmpValSmp */ /* * Copyright (C) 2021 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 * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * This file is part of the RTEMS quality process and was automatically * generated. If you find something that needs to be fixed or * worded better please post a report or patch to an RTEMS mailing list * or raise a bug report: * * https://www.rtems.org/bugs.html * * For information on updating and regenerating please refer to the How-To * section in the Software Requirements Engineering chapter of the * RTEMS Software Engineering manual. The manual is provided as a part of * a release. For development sources please refer to the online * documentation at: * * https://docs.rtems.org */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "tx-support.h" #include /** * @defgroup RTEMSTestCaseScoreSchedSmpValSmp spec:/score/sched/smp/val/smp * * @ingroup RTEMSTestSuiteTestsuitesValidationSmpOnly0 * * @brief Tests SMP-specific scheduler behaviour. * * This test case performs the following actions: * * - Create two worker threads and a mutex. Use the mutex and the worker to * construct the removal of the last processor of a scheduler while a thread * is scheduled. * * - Let worker B help worker A. * * - Restart the worker B to withdraw the help offer and wait on barriers. * Move worker B to scheduler A. Remove the processor while worker A is * scheduled. * * - Clean up all used resources. * * @{ */ /** * @brief Test context for spec:/score/sched/smp/val/smp test case. */ typedef struct { /** * @brief This member contains the runner identifier. */ rtems_id runner_id; /** * @brief This member contains the worker A identifier. */ rtems_id worker_a_id; /** * @brief This member contains the worker B identifier. */ rtems_id worker_b_id; /** * @brief This member contains the mutex identifier. */ rtems_id mutex_id; /** * @brief This member provides the context to wrap thread queue operations. */ WrapThreadQueueContext wrap_tq_ctx; /** * @brief This member contains the call within ISR request. */ CallWithinISRRequest request;; /** * @brief This member contains the barrier to synchronize the runner and the * workers. */ SMP_barrier_Control barrier; } ScoreSchedSmpValSmp_Context; static ScoreSchedSmpValSmp_Context ScoreSchedSmpValSmp_Instance; typedef ScoreSchedSmpValSmp_Context Context; typedef enum { EVENT_OBTAIN = RTEMS_EVENT_0, EVENT_RELEASE = RTEMS_EVENT_1, EVENT_SYNC_RUNNER = RTEMS_EVENT_2, EVENT_RESTART = RTEMS_EVENT_3 } Event; static void Barriers( void *arg ) { Context *ctx; SMP_barrier_State barrier_state; ctx = arg; _SMP_barrier_State_initialize( &barrier_state ); /* A */ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 ); /* B */ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 ); } static void RequestISR( void *arg ) { Context *ctx; ctx = arg; ctx->request.handler = Barriers; ctx->request.arg = ctx; CallWithinISRSubmit( &ctx->request ); } static void WorkerTask( rtems_task_argument arg ) { Context *ctx; ctx = (Context *) arg; while ( true ) { rtems_event_set events; events = ReceiveAnyEvents(); if ( ( events & EVENT_SYNC_RUNNER ) != 0 ) { SendEvents( ctx->runner_id, EVENT_SYNC_RUNNER ); } if ( ( events & EVENT_OBTAIN ) != 0 ) { ObtainMutex( ctx->mutex_id ); } if ( ( events & EVENT_RELEASE ) != 0 ) { ReleaseMutex( ctx->mutex_id ); } if ( ( events & EVENT_RESTART ) != 0 ) { rtems_status_code sc; T_eq_u32( rtems_scheduler_get_processor(), 0 ); SetPriority( ctx->runner_id, PRIO_VERY_HIGH ); T_eq_u32( rtems_scheduler_get_processor(), 1 ); WrapThreadQueueExtract( &ctx->wrap_tq_ctx, GetThread( ctx->worker_b_id ) ); sc = rtems_task_restart( ctx->worker_b_id, (rtems_task_argument) ctx ); T_rsc_success( sc ); T_eq_u32( rtems_scheduler_get_processor(), 0 ); } } } static void ScoreSchedSmpValSmp_Setup( ScoreSchedSmpValSmp_Context *ctx ) { SetSelfPriority( PRIO_NORMAL ); WrapThreadQueueInitialize( &ctx->wrap_tq_ctx, RequestISR, ctx ); } static void ScoreSchedSmpValSmp_Setup_Wrap( void *arg ) { ScoreSchedSmpValSmp_Context *ctx; ctx = arg; ScoreSchedSmpValSmp_Setup( ctx ); } static void ScoreSchedSmpValSmp_Teardown( ScoreSchedSmpValSmp_Context *ctx ) { RestoreRunnerPriority(); WrapThreadQueueDestroy( &ctx->wrap_tq_ctx ); } static void ScoreSchedSmpValSmp_Teardown_Wrap( void *arg ) { ScoreSchedSmpValSmp_Context *ctx; ctx = arg; ScoreSchedSmpValSmp_Teardown( ctx ); } static T_fixture ScoreSchedSmpValSmp_Fixture = { .setup = ScoreSchedSmpValSmp_Setup_Wrap, .stop = NULL, .teardown = ScoreSchedSmpValSmp_Teardown_Wrap, .scope = NULL, .initial_context = &ScoreSchedSmpValSmp_Instance }; /** * @brief Create two worker threads and a mutex. Use the mutex and the worker * to construct the removal of the last processor of a scheduler while a * thread is scheduled. */ static void ScoreSchedSmpValSmp_Action_0( ScoreSchedSmpValSmp_Context *ctx ) { SMP_barrier_State barrier_state; _SMP_barrier_Control_initialize( &ctx->barrier ); _SMP_barrier_State_initialize( &barrier_state ); ctx->runner_id = rtems_task_self(); ctx->mutex_id = CreateMutex(); ctx->worker_a_id = CreateTask( "WRKA", PRIO_HIGH ); StartTask( ctx->worker_a_id, WorkerTask, ctx ); ctx->worker_b_id = CreateTask( "WRKB", PRIO_NORMAL ); SetScheduler( ctx->worker_b_id, SCHEDULER_B_ID, PRIO_NORMAL ); StartTask( ctx->worker_b_id, WorkerTask, ctx ); /* * Let worker B help worker A. */ SendEvents( ctx->worker_a_id, EVENT_OBTAIN ); SendEvents( ctx->worker_b_id, EVENT_SYNC_RUNNER | EVENT_OBTAIN ); ReceiveAllEvents( EVENT_SYNC_RUNNER ); WaitForExecutionStop( ctx->worker_b_id ); /* * Restart the worker B to withdraw the help offer and wait on barriers. Move * worker B to scheduler A. Remove the processor while worker A is * scheduled. */ SendEvents( ctx->worker_a_id, EVENT_RESTART ); /* A */ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 ); SetScheduler( ctx->worker_b_id, SCHEDULER_A_ID, PRIO_HIGH ); RemoveProcessor( SCHEDULER_B_ID, 1 ); /* B */ _SMP_barrier_Wait( &ctx->barrier, &barrier_state, 2 ); /* * Clean up all used resources. */ SetPriority( ctx->runner_id, PRIO_NORMAL ); AddProcessor( SCHEDULER_B_ID, 1 ); SendEvents( ctx->worker_a_id, EVENT_RELEASE ); DeleteTask( ctx->worker_a_id ); DeleteTask( ctx->worker_b_id ); DeleteMutex( ctx->mutex_id ); } /** * @fn void T_case_body_ScoreSchedSmpValSmp( void ) */ T_TEST_CASE_FIXTURE( ScoreSchedSmpValSmp, &ScoreSchedSmpValSmp_Fixture ) { ScoreSchedSmpValSmp_Context *ctx; ctx = T_fixture_context(); ScoreSchedSmpValSmp_Action_0( ctx ); } /** @} */