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 RtemsSemValSmp
0007  */
0008 
0009 /*
0010  * Copyright (C) 2021 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/threaddispatch.h>
0057 
0058 #include "ts-config.h"
0059 #include "tx-support.h"
0060 
0061 #include <rtems/test.h>
0062 
0063 /**
0064  * @defgroup RtemsSemValSmp spec:/rtems/sem/val/smp
0065  *
0066  * @ingroup TestsuitesValidationSmpOnly0
0067  *
0068  * @brief Tests SMP-specific semaphore behaviour.
0069  *
0070  * This test case performs the following actions:
0071  *
0072  * - Create a worker thread and a MrsP mutex.  Use the mutex and the worker to
0073  *   perform a bad sticky thread queue enqueue.
0074  *
0075  * - Create two worker threads, a MrsP mutex, and a priority inheritance mutex.
0076  *   Use the mutexes and the workers to raise the current priority to a higher
0077  *   priority than the ceiling priority of the mutex while one of the workers
0078  *   waits on the mutex.
0079  *
0080  *   - Let the first worker try to obtain the MrsP mutex.  Check that it
0081  *     acquired the ceiling priority.
0082  *
0083  *   - Let the second worker try to obtain the priority inheritance mutex.
0084  *     Check that the first worker inherited the priority from the second
0085  *     worker.
0086  *
0087  *   - Set the real priority of the first worker.  Check that it defines the
0088  *     current priority.
0089  *
0090  *   - Release the MrsP mutex so that the first worker can to obtain it.  It
0091  *     will replace a temporary priority node which is the maximum priority
0092  *     node.  This is the first scenario we want to test.
0093  *
0094  *   - Obtain the MrsP mutex for the runner thread to start the second scenario
0095  *     we would like to test.
0096  *
0097  *   - Let the first worker try to obtain the MrsP mutex.  Check that it
0098  *     acquired the ceiling priority.
0099  *
0100  *   - Let the second worker try to obtain the priority inheritance mutex.
0101  *     Check that the first worker inherited the priority from the second
0102  *     worker.
0103  *
0104  *   - Lower the priority of the second worker.  Check that the inherited
0105  *     priority of the first worker reflects this priority change.
0106  *
0107  *   - Change the real priority of the first worker so that it defines its
0108  *     current priority.
0109  *
0110  *   - Release the MrsP mutex so that the first worker can to obtain it.  It
0111  *     will replace a temporary priority node which is between the minimum and
0112  *     maximum priority node.  This is the second scenario we want to test.
0113  *
0114  *   - Clean up all used resources.
0115  *
0116  * @{
0117  */
0118 
0119 /**
0120  * @brief Test context for spec:/rtems/sem/val/smp test case.
0121  */
0122 typedef struct {
0123   /**
0124    * @brief This member contains the mutex identifier.
0125    */
0126   rtems_id mutex_id;
0127 
0128   /**
0129    * @brief This member contains the second mutex identifier.
0130    */
0131   rtems_id mutex_2_id;
0132 
0133   /**
0134    * @brief If this member is true, then the worker is done.
0135    */
0136   volatile bool done;
0137 
0138   /**
0139    * @brief If this member is true, then the second worker is done.
0140    */
0141   volatile bool done_2;
0142 } RtemsSemValSmp_Context;
0143 
0144 static RtemsSemValSmp_Context
0145   RtemsSemValSmp_Instance;
0146 
0147 typedef RtemsSemValSmp_Context Context;
0148 
0149 static void BadEnqueueFatal(
0150   rtems_fatal_source source,
0151   rtems_fatal_code   code,
0152   void              *arg
0153 )
0154 {
0155   Per_CPU_Control *cpu_self;
0156   Context         *ctx;
0157 
0158   T_eq_int( source, INTERNAL_ERROR_CORE );
0159   T_eq_ulong(
0160     code,
0161     INTERNAL_ERROR_THREAD_QUEUE_ENQUEUE_STICKY_FROM_BAD_STATE
0162   );
0163 
0164   SetFatalHandler( NULL, NULL );
0165 
0166   _ISR_Set_level( 0 );
0167   cpu_self = _Per_CPU_Get();
0168   _Thread_Dispatch_unnest( cpu_self );
0169   _Thread_Dispatch_unnest( cpu_self );
0170 
0171   ctx = arg;
0172   ctx->done = true;
0173   SuspendSelf();
0174 }
0175 
0176 static void BadEnqueueTask( rtems_task_argument arg )
0177 {
0178   Context *ctx;
0179 
0180   ctx = (Context *) arg;
0181   (void) _Thread_Dispatch_disable();
0182   ObtainMutex( ctx->mutex_id );
0183 }
0184 
0185 static void ObtainReleaseMrsPTask( rtems_task_argument arg )
0186 {
0187   Context *ctx;
0188 
0189   ctx = (Context *) arg;
0190   ObtainMutex( ctx->mutex_2_id );
0191   ctx->done = true;
0192   ObtainMutex( ctx->mutex_id );
0193   ReleaseMutex( ctx->mutex_id );
0194   ReleaseMutex( ctx->mutex_2_id );
0195   ctx->done = true;
0196   SuspendSelf();
0197 }
0198 
0199 static void ObtainRelease2Task( rtems_task_argument arg )
0200 {
0201   Context *ctx;
0202 
0203   ctx = (Context *) arg;
0204   ctx->done_2 = true;
0205   ObtainMutex( ctx->mutex_2_id );
0206   ReleaseMutex( ctx->mutex_2_id );
0207   ctx->done_2 = true;
0208   SuspendSelf();
0209 }
0210 
0211 static void RtemsSemValSmp_Setup( RtemsSemValSmp_Context *ctx )
0212 {
0213   SetSelfPriority( PRIO_NORMAL );
0214 }
0215 
0216 static void RtemsSemValSmp_Setup_Wrap( void *arg )
0217 {
0218   RtemsSemValSmp_Context *ctx;
0219 
0220   ctx = arg;
0221   RtemsSemValSmp_Setup( ctx );
0222 }
0223 
0224 static void RtemsSemValSmp_Teardown( RtemsSemValSmp_Context *ctx )
0225 {
0226   RestoreRunnerPriority();
0227 }
0228 
0229 static void RtemsSemValSmp_Teardown_Wrap( void *arg )
0230 {
0231   RtemsSemValSmp_Context *ctx;
0232 
0233   ctx = arg;
0234   RtemsSemValSmp_Teardown( ctx );
0235 }
0236 
0237 static T_fixture RtemsSemValSmp_Fixture = {
0238   .setup = RtemsSemValSmp_Setup_Wrap,
0239   .stop = NULL,
0240   .teardown = RtemsSemValSmp_Teardown_Wrap,
0241   .scope = NULL,
0242   .initial_context = &RtemsSemValSmp_Instance
0243 };
0244 
0245 /**
0246  * @brief Create a worker thread and a MrsP mutex.  Use the mutex and the
0247  *   worker to perform a bad sticky thread queue enqueue.
0248  */
0249 static void RtemsSemValSmp_Action_0( RtemsSemValSmp_Context *ctx )
0250 {
0251   rtems_status_code sc;
0252   rtems_id          worker_id;
0253   rtems_id          scheduler_b_id;
0254 
0255   ctx->done = false;
0256 
0257   sc = rtems_scheduler_ident( TEST_SCHEDULER_B_NAME, &scheduler_b_id );
0258   T_rsc_success( sc );
0259 
0260   sc = rtems_semaphore_create(
0261     rtems_build_name( 'M', 'U', 'T', 'X' ),
0262     1,
0263     RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY |
0264       RTEMS_MULTIPROCESSOR_RESOURCE_SHARING,
0265     PRIO_HIGH,
0266     &ctx->mutex_id
0267   );
0268   T_rsc_success( sc );
0269 
0270   worker_id = CreateTask( "WORK", PRIO_NORMAL );
0271   SetScheduler( worker_id, scheduler_b_id, PRIO_NORMAL );
0272 
0273   ObtainMutex( ctx->mutex_id );
0274   SetFatalHandler( BadEnqueueFatal, ctx );
0275   StartTask( worker_id, BadEnqueueTask, ctx );
0276 
0277   while ( !ctx->done ) {
0278     /* Wait */
0279   }
0280 
0281   DeleteTask( worker_id );
0282   ReleaseMutex( ctx->mutex_id );
0283   DeleteMutex( ctx->mutex_id );
0284 }
0285 
0286 /**
0287  * @brief Create two worker threads, a MrsP mutex, and a priority inheritance
0288  *   mutex. Use the mutexes and the workers to raise the current priority to a
0289  *   higher priority than the ceiling priority of the mutex while one of the
0290  *   workers waits on the mutex.
0291  */
0292 static void RtemsSemValSmp_Action_1( RtemsSemValSmp_Context *ctx )
0293 {
0294   rtems_status_code   sc;
0295   rtems_id            worker_id;
0296   rtems_id            worker_2_id;
0297   rtems_id            scheduler_b_id;
0298   rtems_task_priority prio;
0299 
0300   sc = rtems_scheduler_ident( TEST_SCHEDULER_B_NAME, &scheduler_b_id );
0301   T_rsc_success( sc );
0302 
0303   sc = rtems_semaphore_create(
0304     rtems_build_name( 'M', 'U', 'T', 'X' ),
0305     1,
0306     RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY |
0307       RTEMS_MULTIPROCESSOR_RESOURCE_SHARING,
0308     PRIO_HIGH,
0309     &ctx->mutex_id
0310   );
0311   T_rsc_success( sc );
0312 
0313   sc = rtems_semaphore_set_priority(
0314     ctx->mutex_id,
0315     scheduler_b_id,
0316     PRIO_HIGH,
0317     &prio
0318   );
0319   T_rsc_success( sc );
0320 
0321   ctx->mutex_2_id = CreateMutex();
0322 
0323   worker_id = CreateTask( "WORK", PRIO_NORMAL );
0324   SetScheduler( worker_id, scheduler_b_id, PRIO_NORMAL );
0325 
0326   worker_2_id = CreateTask( "WRK2", PRIO_NORMAL );
0327   SetScheduler( worker_2_id, scheduler_b_id, PRIO_VERY_HIGH );
0328 
0329   /*
0330    * Let the first worker try to obtain the MrsP mutex.  Check that it acquired
0331    * the ceiling priority.
0332    */
0333   ObtainMutex( ctx->mutex_id );
0334   ctx->done = false;
0335   StartTask( worker_id, ObtainReleaseMrsPTask, ctx );
0336 
0337   while ( !ctx->done ) {
0338     /* Wait */
0339   }
0340 
0341   ctx->done = false;
0342   WaitForIntendToBlock( worker_id );
0343   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0344   T_eq_u32( prio, PRIO_HIGH );
0345 
0346   /*
0347    * Let the second worker try to obtain the priority inheritance mutex. Check
0348    * that the first worker inherited the priority from the second worker.
0349    */
0350   ctx->done_2 = false;
0351   StartTask( worker_2_id, ObtainRelease2Task, ctx );
0352 
0353   while ( !ctx->done_2 ) {
0354     /* Wait */
0355   }
0356 
0357   ctx->done_2 = false;
0358   WaitForExecutionStop( worker_2_id );
0359   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0360   T_eq_u32( prio, PRIO_VERY_HIGH );
0361 
0362   /*
0363    * Set the real priority of the first worker.  Check that it defines the
0364    * current priority.
0365    */
0366   SetPriority( worker_id, PRIO_ULTRA_HIGH );
0367 
0368   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0369   T_eq_u32( prio, PRIO_ULTRA_HIGH );
0370 
0371   /*
0372    * Release the MrsP mutex so that the first worker can to obtain it.  It will
0373    * replace a temporary priority node which is the maximum priority node.
0374    * This is the first scenario we want to test.
0375    */
0376   ReleaseMutex( ctx->mutex_id );
0377 
0378   while ( !ctx->done || !ctx->done_2 ) {
0379     /* Wait */
0380   }
0381 
0382   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0383   T_eq_u32( prio, PRIO_ULTRA_HIGH );
0384 
0385   /*
0386    * Obtain the MrsP mutex for the runner thread to start the second scenario
0387    * we would like to test.
0388    */
0389   ObtainMutex( ctx->mutex_id );
0390 
0391   /*
0392    * Let the first worker try to obtain the MrsP mutex.  Check that it acquired
0393    * the ceiling priority.
0394    */
0395   ctx->done = false;
0396   sc = rtems_task_restart( worker_id, (rtems_task_argument) ctx );
0397   T_rsc_success( sc );
0398 
0399   while ( !ctx->done ) {
0400     /* Wait */
0401   }
0402 
0403   ctx->done = false;
0404   WaitForIntendToBlock( worker_id );
0405   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0406   T_eq_u32( prio, PRIO_HIGH );
0407 
0408   /*
0409    * Let the second worker try to obtain the priority inheritance mutex. Check
0410    * that the first worker inherited the priority from the second worker.
0411    */
0412   ctx->done_2 = false;
0413   sc = rtems_task_restart( worker_2_id, (rtems_task_argument) ctx );
0414   T_rsc_success( sc );
0415 
0416   while ( !ctx->done_2 ) {
0417     /* Wait */
0418   }
0419 
0420   ctx->done_2 = false;
0421   WaitForExecutionStop( worker_2_id );
0422   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0423   T_eq_u32( prio, PRIO_VERY_HIGH );
0424 
0425   /*
0426    * Lower the priority of the second worker.  Check that the inherited
0427    * priority of the first worker reflects this priority change.
0428    */
0429   SetPriority( worker_2_id, PRIO_LOW );
0430 
0431   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0432   T_eq_u32( prio, PRIO_HIGH );
0433 
0434   /*
0435    * Change the real priority of the first worker so that it defines its
0436    * current priority.
0437    */
0438   SetPriority( worker_id, PRIO_ULTRA_HIGH );
0439 
0440   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0441   T_eq_u32( prio, PRIO_ULTRA_HIGH );
0442 
0443   /*
0444    * Release the MrsP mutex so that the first worker can to obtain it.  It will
0445    * replace a temporary priority node which is between the minimum and maximum
0446    * priority node.  This is the second scenario we want to test.
0447    */
0448   ReleaseMutex( ctx->mutex_id );
0449 
0450   while ( !ctx->done || !ctx->done_2 ) {
0451     /* Wait */
0452   }
0453 
0454   prio = GetPriorityByScheduler( worker_id, scheduler_b_id );
0455   T_eq_u32( prio, PRIO_ULTRA_HIGH );
0456 
0457   /*
0458    * Clean up all used resources.
0459    */
0460   DeleteTask( worker_id );
0461   DeleteTask( worker_2_id );
0462   DeleteMutex( ctx->mutex_id );
0463   DeleteMutex( ctx->mutex_2_id );
0464 }
0465 
0466 /**
0467  * @fn void T_case_body_RtemsSemValSmp( void )
0468  */
0469 T_TEST_CASE_FIXTURE( RtemsSemValSmp, &RtemsSemValSmp_Fixture )
0470 {
0471   RtemsSemValSmp_Context *ctx;
0472 
0473   ctx = T_fixture_context();
0474 
0475   RtemsSemValSmp_Action_0( ctx );
0476   RtemsSemValSmp_Action_1( ctx );
0477 }
0478 
0479 /** @} */