From 4e3c5b6d973d93733d699df029328ae4bda78221 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 17 Sep 2021 15:09:05 +0200 Subject: validation: Test priority change detail --- .../validation/validation-smp-only-0.yml | 1 + testsuites/validation/tc-score-tq-smp.c | 271 +++++++++++++++++++++ 2 files changed, 272 insertions(+) create mode 100644 testsuites/validation/tc-score-tq-smp.c diff --git a/spec/build/testsuites/validation/validation-smp-only-0.yml b/spec/build/testsuites/validation/validation-smp-only-0.yml index 2beb8e0fd2..bf8b480ab6 100644 --- a/spec/build/testsuites/validation/validation-smp-only-0.yml +++ b/spec/build/testsuites/validation/validation-smp-only-0.yml @@ -16,6 +16,7 @@ source: - testsuites/validation/tc-scheduler-smp-only.c - testsuites/validation/tc-score-smp-per-cpu-jobs.c - testsuites/validation/tc-score-smp-thread.c +- testsuites/validation/tc-score-tq-smp.c - testsuites/validation/tc-sem-smp.c - testsuites/validation/ts-validation-smp-only-0.c stlib: [] diff --git a/testsuites/validation/tc-score-tq-smp.c b/testsuites/validation/tc-score-tq-smp.c new file mode 100644 index 0000000000..2f6218c838 --- /dev/null +++ b/testsuites/validation/tc-score-tq-smp.c @@ -0,0 +1,271 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ + +/** + * @file + * + * @ingroup RTEMSTestCaseScoreTqValSmp + */ + +/* + * 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 "tx-support.h" + +#include + +/** + * @defgroup RTEMSTestCaseScoreTqValSmp spec:/score/tq/val/smp + * + * @ingroup RTEMSTestSuiteTestsuitesValidationSmpOnly0 + * + * @brief Tests SMP-specific thread queue behaviour. + * + * This test case performs the following actions: + * + * - Create two worker threads and a mutex. Use the mutex and the worker to do + * a thread priority change in parallel with a thread queue extraction. + * + * - Create and start worker A on a second processor. Let it obtain the + * mutex. + * + * - Create and start worker B. Let it try to obtain the mutex which is + * owned by worker A. Delete worker B to extract it from the thread queue. + * Wrap the thread queue extract operation to do a parallel thread priority + * change carried out by worker A. + * + * - Clean up all used resources. + * + * @{ + */ + +/** + * @brief Test context for spec:/score/tq/val/smp test case. + */ +typedef struct { + /** + * @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 contains the thread queue of the mutex. + */ + Thread_queue_Queue *thread_queue; + + /** + * @brief This member contains the context to wrap the thread queue extract. + */ + WrapThreadQueueContext wrap; + + /** + * @brief This member contains the barrier to synchronize the runner, worker + * A, and worker B. + */ + SMP_barrier_Control barrier; + + /** + * @brief This member contains the barrier state for the runner processor. + */ + SMP_barrier_State barrier_state; +} ScoreTqValSmp_Context; + +static ScoreTqValSmp_Context + ScoreTqValSmp_Instance; + +static T_fixture ScoreTqValSmp_Fixture = { + .setup = NULL, + .stop = NULL, + .teardown = NULL, + .scope = NULL, + .initial_context = &ScoreTqValSmp_Instance +}; + +typedef ScoreTqValSmp_Context Context; + +static void Extract( void *arg ) +{ + Context *ctx; + unsigned int ticket_0; + unsigned int ticket_1; + + ctx = arg; + + ticket_0 = _Atomic_Load_uint( + &ctx->thread_queue->Lock.next_ticket, + ATOMIC_ORDER_RELAXED + ); + + /* B1 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + + /* + * Ensure that worker A acquired the thread wait lock of worker B. + */ + do { + ticket_1 = _Atomic_Load_uint( + &ctx->thread_queue->Lock.next_ticket, + ATOMIC_ORDER_RELAXED + ); + } while ( ticket_0 == ticket_1 ); + + /* + * Continue with the thread queue extraction. The thread wait lock of + * worker B will be changed back to the default thread wait lock. This + * will cause worker A to release the thread queue lock and acquire the + * default thread wait lock of worker B instead to carry out the priority + * change. + * + * See also _Thread_Wait_acquire_critical(). + */ +} + +static void WorkerA( rtems_task_argument arg ) +{ + Context *ctx; + SMP_barrier_State state; + + ctx = (Context *) arg; + _SMP_barrier_State_initialize( &state ); + + ObtainMutex( ctx->mutex_id ); + + /* B0 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + /* B1 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + SetPriority( ctx->worker_b_id, PRIO_VERY_HIGH ); + ReleaseMutex( ctx->mutex_id ); + + /* B2 */ + _SMP_barrier_Wait( &ctx->barrier, &state, 2 ); + + SuspendSelf(); +} + +static void WorkerB( rtems_task_argument arg ) +{ + Context *ctx; + + ctx = (Context *) arg; + + ObtainMutex( ctx->mutex_id ); +} + +/** + * @brief Create two worker threads and a mutex. Use the mutex and the worker + * to do a thread priority change in parallel with a thread queue extraction. + */ +static void ScoreTqValSmp_Action_0( ScoreTqValSmp_Context *ctx ) +{ + SetSelfPriority( PRIO_NORMAL ); + _SMP_barrier_Control_initialize( &ctx->barrier ); + _SMP_barrier_State_initialize( &ctx->barrier_state ); + WrapThreadQueueInitialize( &ctx->wrap, Extract, ctx ); + + ctx->mutex_id = CreateMutex(); + ctx->thread_queue = GetMutexThreadQueue( ctx->mutex_id ); + + /* + * Create and start worker A on a second processor. Let it obtain the mutex. + */ + ctx->worker_a_id = CreateTask( "WRKA", PRIO_NORMAL ); + SetScheduler( ctx->worker_a_id, SCHEDULER_B_ID, PRIO_NORMAL ); + StartTask( ctx->worker_a_id, WorkerA, ctx ); + + /* B0 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + + /* + * Create and start worker B. Let it try to obtain the mutex which is owned + * by worker A. Delete worker B to extract it from the thread queue. Wrap + * the thread queue extract operation to do a parallel thread priority change + * carried out by worker A. + */ + ctx->worker_b_id = CreateTask( "WRKB", PRIO_HIGH ); + StartTask( ctx->worker_b_id, WorkerB, ctx ); + WrapThreadQueueExtractDirect( &ctx->wrap, GetThread( ctx->worker_b_id ) ); + DeleteTask( ctx->worker_b_id ); + + /* + * Clean up all used resources. + */ + /* B2 */ + _SMP_barrier_Wait( &ctx->barrier, &ctx->barrier_state, 2 ); + + DeleteTask( ctx->worker_a_id ); + DeleteMutex( ctx->mutex_id ); + WrapThreadQueueDestroy( &ctx->wrap ); + RestoreRunnerPriority(); +} + +/** + * @fn void T_case_body_ScoreTqValSmp( void ) + */ +T_TEST_CASE_FIXTURE( ScoreTqValSmp, &ScoreTqValSmp_Fixture ) +{ + ScoreTqValSmp_Context *ctx; + + ctx = T_fixture_context(); + + ScoreTqValSmp_Action_0( ctx ); +} + +/** @} */ -- cgit v1.2.3