Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup ScoreTqReqFlushPriorityInherit
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 "tr-tq-flush-priority-inherit.h"
0056 #include "tx-support.h"
0057 
0058 #include <rtems/test.h>
0059 
0060 /**
0061  * @defgroup ScoreTqReqFlushPriorityInherit \
0062  *   spec:/score/tq/req/flush-priority-inherit
0063  *
0064  * @ingroup TestsuitesValidationNoClock0
0065  *
0066  * @{
0067  */
0068 
0069 typedef struct {
0070   uint8_t Skip : 1;
0071   uint8_t Pre_Priority_NA : 1;
0072   uint8_t Pre_Queue_NA : 1;
0073   uint8_t Post_Extract : 2;
0074   uint8_t Post_PriorityUpdate : 2;
0075 } ScoreTqReqFlushPriorityInherit_Entry;
0076 
0077 /**
0078  * @brief Test context for spec:/score/tq/req/flush-priority-inherit test case.
0079  */
0080 typedef struct {
0081   /**
0082    * @brief This member contains the call within ISR request.
0083    */
0084   CallWithinISRRequest request;
0085 
0086   /**
0087    * @brief If this member is true, then a minimum priority of the owner of the
0088    *   thread queue shall be inherited from a thread enqueued on the thread
0089    *   queue.
0090    */
0091   bool minimum;
0092 
0093   /**
0094    * @brief This member contains a copy of the corresponding
0095    *   ScoreTqReqFlushPriorityInherit_Run() parameter.
0096    */
0097   TQContext *tq_ctx;
0098 
0099   struct {
0100     /**
0101      * @brief This member defines the pre-condition indices for the next
0102      *   action.
0103      */
0104     size_t pci[ 2 ];
0105 
0106     /**
0107      * @brief This member defines the pre-condition states for the next action.
0108      */
0109     size_t pcs[ 2 ];
0110 
0111     /**
0112      * @brief If this member is true, then the test action loop is executed.
0113      */
0114     bool in_action_loop;
0115 
0116     /**
0117      * @brief This member contains the next transition map index.
0118      */
0119     size_t index;
0120 
0121     /**
0122      * @brief This member contains the current transition map entry.
0123      */
0124     ScoreTqReqFlushPriorityInherit_Entry entry;
0125 
0126     /**
0127      * @brief If this member is true, then the current transition variant
0128      *   should be skipped.
0129      */
0130     bool skip;
0131   } Map;
0132 } ScoreTqReqFlushPriorityInherit_Context;
0133 
0134 static ScoreTqReqFlushPriorityInherit_Context
0135   ScoreTqReqFlushPriorityInherit_Instance;
0136 
0137 static const char * const ScoreTqReqFlushPriorityInherit_PreDesc_Priority[] = {
0138   "Minimum",
0139   "NotMinimum",
0140   "NA"
0141 };
0142 
0143 static const char * const ScoreTqReqFlushPriorityInherit_PreDesc_Queue[] = {
0144   "Empty",
0145   "NonEmpty",
0146   "NA"
0147 };
0148 
0149 static const char * const * const ScoreTqReqFlushPriorityInherit_PreDesc[] = {
0150   ScoreTqReqFlushPriorityInherit_PreDesc_Priority,
0151   ScoreTqReqFlushPriorityInherit_PreDesc_Queue,
0152   NULL
0153 };
0154 
0155 typedef ScoreTqReqFlushPriorityInherit_Context Context;
0156 
0157 static const T_scheduler_event *GetUnblock( Context *ctx, size_t *index )
0158 {
0159   return TQGetNextUnblock( ctx->tq_ctx, index );
0160 }
0161 
0162 static const T_scheduler_event *GetPriorityUpdate( Context *ctx, size_t *index )
0163 {
0164   return T_scheduler_next(
0165     &ctx->tq_ctx->scheduler_log.header,
0166     T_SCHEDULER_UPDATE_PRIORITY,
0167     index
0168   );
0169 }
0170 
0171 static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker )
0172 {
0173   return ctx->tq_ctx->worker_tcb[ worker ];
0174 }
0175 
0176 static void Flush( void *arg )
0177 {
0178   Context *ctx;
0179 
0180   ctx = arg;
0181   TQSchedulerRecordStart( ctx->tq_ctx );
0182   TQFlush( ctx->tq_ctx, true );
0183 }
0184 
0185 static void SchedulerEvent(
0186   void                    *arg,
0187   const T_scheduler_event *event,
0188   T_scheduler_when         when
0189 )
0190 {
0191   Context *ctx;
0192 
0193   ctx = arg;
0194 
0195   if (
0196     when == T_SCHEDULER_BEFORE &&
0197     event->operation == T_SCHEDULER_BLOCK
0198   ) {
0199     ctx->request.handler = Flush;
0200     ctx->request.arg = ctx;
0201     CallWithinISRSubmit( &ctx->request );
0202     T_scheduler_set_event_handler( NULL, NULL );
0203   }
0204 }
0205 
0206 static void ScoreTqReqFlushPriorityInherit_Pre_Priority_Prepare(
0207   ScoreTqReqFlushPriorityInherit_Context     *ctx,
0208   ScoreTqReqFlushPriorityInherit_Pre_Priority state
0209 )
0210 {
0211   switch ( state ) {
0212     case ScoreTqReqFlushPriorityInherit_Pre_Priority_Minimum: {
0213       /*
0214        * While a minimum priority of the owner of the thread queue is inherited
0215        * from a thread enqueued on the thread queue.
0216        */
0217       ctx->minimum = true;
0218       break;
0219     }
0220 
0221     case ScoreTqReqFlushPriorityInherit_Pre_Priority_NotMinimum: {
0222       /*
0223        * While no minimum priority of the owner of the thread queue is
0224        * inherited from a thread enqueued on the thread queue.
0225        */
0226       ctx->minimum = false;
0227       break;
0228     }
0229 
0230     case ScoreTqReqFlushPriorityInherit_Pre_Priority_NA:
0231       break;
0232   }
0233 }
0234 
0235 static void ScoreTqReqFlushPriorityInherit_Pre_Queue_Prepare(
0236   ScoreTqReqFlushPriorityInherit_Context  *ctx,
0237   ScoreTqReqFlushPriorityInherit_Pre_Queue state
0238 )
0239 {
0240   switch ( state ) {
0241     case ScoreTqReqFlushPriorityInherit_Pre_Queue_Empty: {
0242       /*
0243        * While the thread queue is empty.
0244        */
0245       ctx->tq_ctx->how_many = 0;
0246       break;
0247     }
0248 
0249     case ScoreTqReqFlushPriorityInherit_Pre_Queue_NonEmpty: {
0250       /*
0251        * While the thread queue has at least one enqueued thread.
0252        */
0253       ctx->tq_ctx->how_many = 3;
0254       break;
0255     }
0256 
0257     case ScoreTqReqFlushPriorityInherit_Pre_Queue_NA:
0258       break;
0259   }
0260 }
0261 
0262 static void ScoreTqReqFlushPriorityInherit_Post_Extract_Check(
0263   ScoreTqReqFlushPriorityInherit_Context     *ctx,
0264   ScoreTqReqFlushPriorityInherit_Post_Extract state
0265 )
0266 {
0267   size_t                   i;
0268   const T_scheduler_event *event;
0269 
0270   i = 0;
0271 
0272   switch ( state ) {
0273     case ScoreTqReqFlushPriorityInherit_Post_Extract_Nop: {
0274       /*
0275        * No operation shall be performed.
0276        */
0277       /* Event receive */
0278       T_eq_ptr( GetUnblock( ctx, &i )->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
0279       T_eq_ptr( GetPriorityUpdate( ctx, &i ), &T_scheduler_event_null );
0280       break;
0281     }
0282 
0283     case ScoreTqReqFlushPriorityInherit_Post_Extract_All: {
0284       /*
0285        * The enqueued threads of the thread queue shall be extracted in
0286        * priority order for each priority queue associated with a scheduler.
0287        * The priority queues of the thread queue shall be accessed in FIFO
0288        * order.
0289        */
0290       event = GetUnblock( ctx, &i );
0291       T_eq_ptr( event->executing, NULL );
0292       T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_D ) );
0293 
0294       event = GetUnblock( ctx, &i );
0295       T_eq_ptr( event->executing, NULL );
0296       T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_C ) );
0297 
0298       if ( ctx->minimum ) {
0299         /*
0300          * This priority update is carried out by
0301          * _Thread_queue_Flush_critical().
0302          */
0303         event = GetPriorityUpdate( ctx, &i );
0304         T_eq_ptr( event->executing, NULL );
0305         T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
0306       }
0307 
0308       event = GetUnblock( ctx, &i );
0309       T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_B ) );
0310       T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_B ) );
0311 
0312       if ( ctx->minimum && rtems_configuration_get_maximum_processors() > 1 ) {
0313         /*
0314          * This superfluous priority update is carried out by
0315          * _Thread_queue_Enqueue() since TQ_BLOCKER_B would have inherited its
0316          * priority for scheduler B to TQ_BLOCKER_A if it were not flushed from
0317          * the thread queue.
0318          */
0319         event = GetPriorityUpdate( ctx, &i );
0320         T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_B ) );
0321         T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
0322       }
0323 
0324       event = GetPriorityUpdate( ctx, &i );
0325       T_eq_ptr( event, &T_scheduler_event_null );
0326 
0327       T_eq_u32(
0328         GetPriority( ctx->tq_ctx->worker_id[ TQ_BLOCKER_A ] ),
0329         PRIO_HIGH
0330       );
0331       break;
0332     }
0333 
0334     case ScoreTqReqFlushPriorityInherit_Post_Extract_NA:
0335       break;
0336   }
0337 }
0338 
0339 static void ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_Check(
0340   ScoreTqReqFlushPriorityInherit_Context            *ctx,
0341   ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate state
0342 )
0343 {
0344   switch ( state ) {
0345     case ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_No: {
0346       /*
0347        * The current priority of the owner of the thread queue shall not be
0348        * updated by the thread queue flush operation.
0349        */
0350       /* Checked by ``Extract`` post-condition state ``Nop`` */
0351       break;
0352     }
0353 
0354     case ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_Yes: {
0355       /*
0356        * The current priority of the owner of the thread queue shall be updated
0357        * by the thread queue flush operation to reflect the loss of inherited
0358        * priorities of the flushed threads.
0359        */
0360       /* Checked by ``Extract`` post-condition state ``All`` */
0361       break;
0362     }
0363 
0364     case ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_NA:
0365       break;
0366   }
0367 }
0368 
0369 static void ScoreTqReqFlushPriorityInherit_Setup(
0370   ScoreTqReqFlushPriorityInherit_Context *ctx
0371 )
0372 {
0373   TQReset( ctx->tq_ctx );
0374   TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_A, PRIO_HIGH );
0375 }
0376 
0377 static void ScoreTqReqFlushPriorityInherit_Setup_Wrap( void *arg )
0378 {
0379   ScoreTqReqFlushPriorityInherit_Context *ctx;
0380 
0381   ctx = arg;
0382   ctx->Map.in_action_loop = false;
0383   ScoreTqReqFlushPriorityInherit_Setup( ctx );
0384 }
0385 
0386 static void ScoreTqReqFlushPriorityInherit_Teardown(
0387   ScoreTqReqFlushPriorityInherit_Context *ctx
0388 )
0389 {
0390   TQReset( ctx->tq_ctx );
0391 }
0392 
0393 static void ScoreTqReqFlushPriorityInherit_Teardown_Wrap( void *arg )
0394 {
0395   ScoreTqReqFlushPriorityInherit_Context *ctx;
0396 
0397   ctx = arg;
0398   ctx->Map.in_action_loop = false;
0399   ScoreTqReqFlushPriorityInherit_Teardown( ctx );
0400 }
0401 
0402 static void ScoreTqReqFlushPriorityInherit_Action(
0403   ScoreTqReqFlushPriorityInherit_Context *ctx
0404 )
0405 {
0406   TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_PREPARE );
0407 
0408   if ( ctx->tq_ctx->how_many > 0 ) {
0409     if ( ctx->minimum ) {
0410       if ( rtems_configuration_get_maximum_processors() > 1 ) {
0411         TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_B, SCHEDULER_B_ID, PRIO_HIGH );
0412       } else {
0413         TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_B, SCHEDULER_A_ID, PRIO_HIGH );
0414       }
0415 
0416       TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_C, PRIO_VERY_HIGH );
0417       TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_D, PRIO_ULTRA_HIGH );
0418       TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE );
0419       TQSend( ctx->tq_ctx, TQ_BLOCKER_D, TQ_EVENT_ENQUEUE );
0420     } else {
0421       TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_B, SCHEDULER_A_ID, PRIO_HIGH );
0422       TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_C, PRIO_HIGH );
0423       TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_D, PRIO_HIGH );
0424 
0425       TQSend( ctx->tq_ctx, TQ_BLOCKER_D, TQ_EVENT_ENQUEUE );
0426       TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE );
0427     }
0428 
0429     T_scheduler_set_event_handler( SchedulerEvent, ctx );
0430     TQSendAndWaitForExecutionStop(
0431       ctx->tq_ctx,
0432       TQ_BLOCKER_B,
0433       TQ_EVENT_ENQUEUE
0434     );
0435   } else {
0436     TQSchedulerRecordStart( ctx->tq_ctx );
0437     TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL );
0438   }
0439 
0440   TQSchedulerRecordStop( ctx->tq_ctx );
0441   TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_DONE );
0442 }
0443 
0444 static const ScoreTqReqFlushPriorityInherit_Entry
0445 ScoreTqReqFlushPriorityInherit_Entries[] = {
0446   { 0, 1, 0, ScoreTqReqFlushPriorityInherit_Post_Extract_Nop,
0447     ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_No },
0448   { 0, 0, 0, ScoreTqReqFlushPriorityInherit_Post_Extract_All,
0449     ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_Yes },
0450   { 0, 0, 0, ScoreTqReqFlushPriorityInherit_Post_Extract_All,
0451     ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_No }
0452 };
0453 
0454 static const uint8_t
0455 ScoreTqReqFlushPriorityInherit_Map[] = {
0456   0, 1, 0, 2
0457 };
0458 
0459 static size_t ScoreTqReqFlushPriorityInherit_Scope(
0460   void  *arg,
0461   char  *buf,
0462   size_t n
0463 )
0464 {
0465   ScoreTqReqFlushPriorityInherit_Context *ctx;
0466 
0467   ctx = arg;
0468 
0469   if ( ctx->Map.in_action_loop ) {
0470     return T_get_scope(
0471       ScoreTqReqFlushPriorityInherit_PreDesc,
0472       buf,
0473       n,
0474       ctx->Map.pcs
0475     );
0476   }
0477 
0478   return 0;
0479 }
0480 
0481 static T_fixture ScoreTqReqFlushPriorityInherit_Fixture = {
0482   .setup = ScoreTqReqFlushPriorityInherit_Setup_Wrap,
0483   .stop = NULL,
0484   .teardown = ScoreTqReqFlushPriorityInherit_Teardown_Wrap,
0485   .scope = ScoreTqReqFlushPriorityInherit_Scope,
0486   .initial_context = &ScoreTqReqFlushPriorityInherit_Instance
0487 };
0488 
0489 static inline ScoreTqReqFlushPriorityInherit_Entry
0490 ScoreTqReqFlushPriorityInherit_PopEntry(
0491   ScoreTqReqFlushPriorityInherit_Context *ctx
0492 )
0493 {
0494   size_t index;
0495 
0496   index = ctx->Map.index;
0497   ctx->Map.index = index + 1;
0498   return ScoreTqReqFlushPriorityInherit_Entries[
0499     ScoreTqReqFlushPriorityInherit_Map[ index ]
0500   ];
0501 }
0502 
0503 static void ScoreTqReqFlushPriorityInherit_SetPreConditionStates(
0504   ScoreTqReqFlushPriorityInherit_Context *ctx
0505 )
0506 {
0507   if ( ctx->Map.entry.Pre_Priority_NA ) {
0508     ctx->Map.pcs[ 0 ] = ScoreTqReqFlushPriorityInherit_Pre_Priority_NA;
0509   } else {
0510     ctx->Map.pcs[ 0 ] = ctx->Map.pci[ 0 ];
0511   }
0512 
0513   ctx->Map.pcs[ 1 ] = ctx->Map.pci[ 1 ];
0514 }
0515 
0516 static void ScoreTqReqFlushPriorityInherit_TestVariant(
0517   ScoreTqReqFlushPriorityInherit_Context *ctx
0518 )
0519 {
0520   ScoreTqReqFlushPriorityInherit_Pre_Priority_Prepare(
0521     ctx,
0522     ctx->Map.pcs[ 0 ]
0523   );
0524   ScoreTqReqFlushPriorityInherit_Pre_Queue_Prepare( ctx, ctx->Map.pcs[ 1 ] );
0525   ScoreTqReqFlushPriorityInherit_Action( ctx );
0526   ScoreTqReqFlushPriorityInherit_Post_Extract_Check(
0527     ctx,
0528     ctx->Map.entry.Post_Extract
0529   );
0530   ScoreTqReqFlushPriorityInherit_Post_PriorityUpdate_Check(
0531     ctx,
0532     ctx->Map.entry.Post_PriorityUpdate
0533   );
0534 }
0535 
0536 static T_fixture_node ScoreTqReqFlushPriorityInherit_Node;
0537 
0538 static T_remark ScoreTqReqFlushPriorityInherit_Remark = {
0539   .next = NULL,
0540   .remark = "ScoreTqReqFlushPriorityInherit"
0541 };
0542 
0543 void ScoreTqReqFlushPriorityInherit_Run( TQContext *tq_ctx )
0544 {
0545   ScoreTqReqFlushPriorityInherit_Context *ctx;
0546 
0547   ctx = &ScoreTqReqFlushPriorityInherit_Instance;
0548   ctx->tq_ctx = tq_ctx;
0549 
0550   ctx = T_push_fixture(
0551     &ScoreTqReqFlushPriorityInherit_Node,
0552     &ScoreTqReqFlushPriorityInherit_Fixture
0553   );
0554   ctx->Map.in_action_loop = true;
0555   ctx->Map.index = 0;
0556 
0557   for (
0558     ctx->Map.pci[ 0 ] = ScoreTqReqFlushPriorityInherit_Pre_Priority_Minimum;
0559     ctx->Map.pci[ 0 ] < ScoreTqReqFlushPriorityInherit_Pre_Priority_NA;
0560     ++ctx->Map.pci[ 0 ]
0561   ) {
0562     for (
0563       ctx->Map.pci[ 1 ] = ScoreTqReqFlushPriorityInherit_Pre_Queue_Empty;
0564       ctx->Map.pci[ 1 ] < ScoreTqReqFlushPriorityInherit_Pre_Queue_NA;
0565       ++ctx->Map.pci[ 1 ]
0566     ) {
0567       ctx->Map.entry = ScoreTqReqFlushPriorityInherit_PopEntry( ctx );
0568       ScoreTqReqFlushPriorityInherit_SetPreConditionStates( ctx );
0569       ScoreTqReqFlushPriorityInherit_TestVariant( ctx );
0570     }
0571   }
0572 
0573   T_add_remark( &ScoreTqReqFlushPriorityInherit_Remark );
0574   T_pop_fixture();
0575 }
0576 
0577 /** @} */