Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:52

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup ScoreThreadValThread
0007  */
0008 
0009 /*
0010  * Copyright (C) 2021, 2023 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 /*
0035  * This file is part of the RTEMS quality process and was automatically
0036  * generated.  If you find something that needs to be fixed or
0037  * worded better please post a report or patch to an RTEMS mailing list
0038  * or raise a bug report:
0039  *
0040  * https://www.rtems.org/bugs.html
0041  *
0042  * For information on updating and regenerating please refer to the How-To
0043  * section in the Software Requirements Engineering chapter of the
0044  * RTEMS Software Engineering manual.  The manual is provided as a part of
0045  * a release.  For development sources please refer to the online
0046  * documentation at:
0047  *
0048  * https://docs.rtems.org
0049  */
0050 
0051 #ifdef HAVE_CONFIG_H
0052 #include "config.h"
0053 #endif
0054 
0055 #include <rtems.h>
0056 #include <rtems/score/statesimpl.h>
0057 #include <rtems/score/threadimpl.h>
0058 
0059 #include "ts-config.h"
0060 #include "tx-support.h"
0061 
0062 #include <rtems/test.h>
0063 
0064 /**
0065  * @defgroup ScoreThreadValThread spec:/score/thread/val/thread
0066  *
0067  * @ingroup TestsuitesValidationNoClock0
0068  *
0069  * @brief Tests general thread behaviour.
0070  *
0071  * This test case performs the following actions:
0072  *
0073  * - Create an extension set with a thread terminate extension which deletes
0074  *   the killer task if it is invoked for the worker task.  Create and start
0075  *   the worker task.  Create and start the killer task.  The killer task
0076  *   deletes the worker task.
0077  *
0078  *   - Check that the killer task was deleted.
0079  *
0080  *   - Check that the worker task still exists.
0081  *
0082  *   - Check that the life of the worker task is protected and terminating.
0083  *
0084  *   - Check that the worker task is waiting for a joining thread.
0085  *
0086  *   - Delete the worker task using brute force.
0087  *
0088  *   - Clean up all used resources.
0089  *
0090  * - Delete a thread which least recently used the floating point coprocessor.
0091  *
0092  *   - Start the worker thread.  Let it use the floating point coprocessor.
0093  *
0094  *   - Delete the worker thread and free the thread resources.
0095  *
0096  *   - Clean up all used resources.
0097  *
0098  * - Validate the global construction.  Mark that the test case executed.
0099  *
0100  *   - Check that the global constructor was called exactly once.
0101  *
0102  *   - Check that the global construction was done by the Classic API user
0103  *     initialization task.
0104  *
0105  *   - Check that the global constructor was called before the task entry.
0106  *
0107  * - Validate that thread dispatching does not recurse.  Issue a couple of
0108  *   thread context switches during a thread dispatch.  Record the stack
0109  *   pointers of the heir threads.
0110  *
0111  *   - Check that the thread dispatching did not recurse through the recorded
0112  *     stack pointers.
0113  *
0114  * @{
0115  */
0116 
0117 /**
0118  * @brief Test context for spec:/score/thread/val/thread test case.
0119  */
0120 typedef struct {
0121   /**
0122    * @brief This member contains the worker task identifier.
0123    */
0124   rtems_id worker_id;
0125 
0126   /**
0127    * @brief This member contains the killer task identifier.
0128    */
0129   rtems_id killer_id;
0130 
0131   /**
0132    * @brief This member contains a floating-point object.
0133    */
0134   volatile double fp_obj;
0135 
0136   /**
0137    * @brief This member indicates the thread switch state.
0138    */
0139   int thread_switch_state;
0140 
0141   /**
0142    * @brief This member contain the runner stack pointer at the context switch.
0143    */
0144   uintptr_t runner_stack[ 2 ];
0145 
0146   /**
0147    * @brief This member contain the worker stack pointer at the context switch.
0148    */
0149   uintptr_t worker_stack[ 2 ];
0150 } ScoreThreadValThread_Context;
0151 
0152 static ScoreThreadValThread_Context
0153   ScoreThreadValThread_Instance;
0154 
0155 typedef ScoreThreadValThread_Context Context;
0156 
0157 static bool test_case_executed;
0158 
0159 static bool constructor_test_case_executed;
0160 
0161 static uint32_t constructor_calls;
0162 
0163 static rtems_id constructor_id;
0164 
0165 static __attribute__(( __constructor__ )) void Constructor( void )
0166 {
0167   constructor_test_case_executed = test_case_executed;
0168   ++constructor_calls;
0169   constructor_id = rtems_task_self();
0170 }
0171 
0172 static void TaskTerminate( rtems_tcb *executing )
0173 {
0174   Context *ctx;
0175 
0176   ctx = T_fixture_context();
0177 
0178   if ( ctx->worker_id == executing->Object.id ) {
0179     DeleteTask( ctx->killer_id );
0180   }
0181 }
0182 
0183 static void WorkerTask( rtems_task_argument arg )
0184 {
0185   (void) arg;
0186   SuspendSelf();
0187 }
0188 
0189 static void GoBackToRunner( void *arg )
0190 {
0191   Context *ctx;
0192 
0193   ctx = arg;
0194   SetPriority( ctx->worker_id, PRIO_LOW );
0195 }
0196 
0197 static void FloatingPointTask( rtems_task_argument arg )
0198 {
0199   Context *ctx;
0200 
0201   ctx = (Context *) arg;
0202   ctx->fp_obj *= 1.23;
0203 
0204   /*
0205    * We use an interrupt to go back to the runner since on some
0206    * architectures, the floating-point context is only saved during interrupt
0207    * processing and not for synchronous thread switches.
0208    */
0209   CallWithinISR( GoBackToRunner, ctx );
0210 }
0211 
0212 static void KillerTask( rtems_task_argument arg )
0213 {
0214   Context *ctx;
0215 
0216   ctx = (Context *) arg;
0217   DeleteTask( ctx->worker_id );
0218 }
0219 
0220 static void TaskSwitch( rtems_tcb *executing, rtems_tcb *heir )
0221 {
0222   Context  *ctx;
0223   rtems_id  worker_id;
0224   int       state;
0225   uintptr_t heir_stack;
0226 
0227   ctx = T_fixture_context();
0228   worker_id = ctx->worker_id;
0229   state = ctx->thread_switch_state;
0230   ctx->thread_switch_state = state + 1;
0231   heir_stack = _CPU_Context_Get_SP( &heir->Registers );
0232 
0233   switch ( state ) {
0234     case 0:
0235       T_eq_u32( heir->Object.id, worker_id );
0236       SuspendTask( worker_id );
0237       ctx->worker_stack[ 0 ] = heir_stack;
0238       break;
0239     case 1:
0240       T_eq_u32( executing->Object.id, worker_id );
0241       ResumeTask( worker_id );
0242       ctx->runner_stack[ 0 ] = heir_stack;
0243       break;
0244     case 2:
0245       T_eq_u32( heir->Object.id, worker_id );
0246       SuspendTask( worker_id );
0247       ctx->worker_stack[ 1 ] = heir_stack;
0248       break;
0249     case 3:
0250       T_eq_u32( executing->Object.id, worker_id );
0251       ctx->runner_stack[ 1 ] = heir_stack;
0252       break;
0253     default:
0254       T_unreachable();
0255   }
0256 }
0257 
0258 static T_fixture ScoreThreadValThread_Fixture = {
0259   .setup = NULL,
0260   .stop = NULL,
0261   .teardown = NULL,
0262   .scope = NULL,
0263   .initial_context = &ScoreThreadValThread_Instance
0264 };
0265 
0266 /**
0267  * @brief Create an extension set with a thread terminate extension which
0268  *   deletes the killer task if it is invoked for the worker task.  Create and
0269  *   start the worker task.  Create and start the killer task.  The killer task
0270  *   deletes the worker task.
0271  */
0272 static void ScoreThreadValThread_Action_0( ScoreThreadValThread_Context *ctx )
0273 {
0274   rtems_extensions_table table = {
0275     .thread_terminate = TaskTerminate
0276   };
0277   rtems_status_code sc;
0278   rtems_id          id;
0279   rtems_tcb        *worker_tcb;
0280 
0281   sc = rtems_extension_create(
0282     rtems_build_name( 'T', 'E', 'S', 'T' ),
0283     &table,
0284     &id
0285   );
0286   T_rsc_success( sc );
0287 
0288   SetSelfPriority( PRIO_NORMAL );
0289   ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
0290   worker_tcb = GetThread( ctx->worker_id );
0291   StartTask( ctx->worker_id, WorkerTask, NULL );
0292   ctx->killer_id = CreateTask( "KILL", PRIO_HIGH );
0293   StartTask( ctx->killer_id, KillerTask, ctx );
0294 
0295   /*
0296    * Check that the killer task was deleted.
0297    */
0298   sc = rtems_event_send( ctx->killer_id, RTEMS_EVENT_0 );
0299   T_rsc( sc, RTEMS_INVALID_ID );
0300 
0301   /*
0302    * Check that the worker task still exists.
0303    */
0304   sc = rtems_event_send( ctx->worker_id, RTEMS_EVENT_0 );
0305   T_rsc_success( sc );
0306 
0307   /*
0308    * Check that the life of the worker task is protected and terminating.
0309    */
0310   T_eq_int(
0311     worker_tcb->Life.state,
0312     THREAD_LIFE_PROTECTED | THREAD_LIFE_TERMINATING
0313   );
0314 
0315   /*
0316    * Check that the worker task is waiting for a joining thread.
0317    */
0318   T_eq_u32(
0319     worker_tcb->current_state,
0320     STATES_WAITING_FOR_JOIN_AT_EXIT
0321   );
0322 
0323   /*
0324    * Delete the worker task using brute force.
0325    */
0326   worker_tcb->Life.state = THREAD_LIFE_DETACHED |
0327     THREAD_LIFE_PROTECTED | THREAD_LIFE_TERMINATING;
0328   _Thread_Clear_state( worker_tcb, STATES_WAITING_FOR_JOIN_AT_EXIT );
0329 
0330   /*
0331    * Clean up all used resources.
0332    */
0333   KillZombies();
0334   RestoreRunnerPriority();
0335 
0336   sc = rtems_extension_delete( id );
0337   T_rsc_success( sc );
0338 }
0339 
0340 /**
0341  * @brief Delete a thread which least recently used the floating point
0342  *   coprocessor.
0343  */
0344 static void ScoreThreadValThread_Action_1( ScoreThreadValThread_Context *ctx )
0345 {
0346   rtems_status_code sc;
0347 
0348   SetSelfPriority( PRIO_NORMAL );
0349   sc = rtems_task_create(
0350     rtems_build_name( 'W', 'O', 'R', 'K'),
0351     PRIO_HIGH,
0352     TEST_MINIMUM_STACK_SIZE,
0353     RTEMS_DEFAULT_MODES,
0354     RTEMS_FLOATING_POINT,
0355     &ctx->worker_id
0356   );
0357   T_rsc_success( sc );
0358 
0359   /*
0360    * Start the worker thread.  Let it use the floating point coprocessor.
0361    */
0362   StartTask( ctx->worker_id, FloatingPointTask, ctx );
0363 
0364   /*
0365    * Delete the worker thread and free the thread resources.
0366    */
0367   DeleteTask( ctx->worker_id );
0368   KillZombies();
0369 
0370   /*
0371    * Clean up all used resources.
0372    */
0373   RestoreRunnerPriority();
0374 }
0375 
0376 /**
0377  * @brief Validate the global construction.  Mark that the test case executed.
0378  */
0379 static void ScoreThreadValThread_Action_2( ScoreThreadValThread_Context *ctx )
0380 {
0381   test_case_executed = true;
0382 
0383   /*
0384    * Check that the global constructor was called exactly once.
0385    */
0386   T_eq_u32( constructor_calls, 1 );
0387 
0388   /*
0389    * Check that the global construction was done by the Classic API user
0390    * initialization task.
0391    */
0392   T_eq_u32( constructor_id, rtems_task_self() );
0393 
0394   /*
0395    * Check that the global constructor was called before the task entry.
0396    */
0397   T_false( constructor_test_case_executed );
0398 }
0399 
0400 /**
0401  * @brief Validate that thread dispatching does not recurse.  Issue a couple of
0402  *   thread context switches during a thread dispatch.  Record the stack
0403  *   pointers of the heir threads.
0404  */
0405 static void ScoreThreadValThread_Action_3( ScoreThreadValThread_Context *ctx )
0406 {
0407   SetSelfPriority( PRIO_NORMAL );
0408   ctx->worker_id = CreateTask( "WORK", PRIO_HIGH );
0409   StartTask( ctx->worker_id, WorkerTask, NULL );
0410 
0411   ctx->thread_switch_state = 0;
0412   ctx->runner_stack[ 0 ] = 0;
0413   ctx->runner_stack[ 1 ] = 1;
0414   ctx->worker_stack[ 0 ] = 0;
0415   ctx->worker_stack[ 1 ] = 1;
0416   SetTaskSwitchExtension( TaskSwitch );
0417   ResumeTask( ctx->worker_id );
0418 
0419   SetTaskSwitchExtension( NULL );
0420   DeleteTask( ctx->worker_id );
0421   RestoreRunnerPriority();
0422 
0423   /*
0424    * Check that the thread dispatching did not recurse through the recorded
0425    * stack pointers.
0426    */
0427   T_eq_uptr( ctx->runner_stack[ 0 ], ctx->runner_stack[ 1 ] );
0428   T_eq_uptr( ctx->worker_stack[ 0 ], ctx->worker_stack[ 1 ] );
0429 }
0430 
0431 /**
0432  * @fn void T_case_body_ScoreThreadValThread( void )
0433  */
0434 T_TEST_CASE_FIXTURE( ScoreThreadValThread, &ScoreThreadValThread_Fixture )
0435 {
0436   ScoreThreadValThread_Context *ctx;
0437 
0438   ctx = T_fixture_context();
0439 
0440   ScoreThreadValThread_Action_0( ctx );
0441   ScoreThreadValThread_Action_1( ctx );
0442   ScoreThreadValThread_Action_2( ctx );
0443   ScoreThreadValThread_Action_3( ctx );
0444 }
0445 
0446 /** @} */