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 ScoreTqReqFlushPriority
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.h"
0056 #include "tx-support.h"
0057 
0058 #include <rtems/test.h>
0059 
0060 /**
0061  * @defgroup ScoreTqReqFlushPriority spec:/score/tq/req/flush-priority
0062  *
0063  * @ingroup TestsuitesValidationNoClock0
0064  *
0065  * @{
0066  */
0067 
0068 typedef struct {
0069   uint8_t Skip : 1;
0070   uint8_t Pre_Queue_NA : 1;
0071   uint8_t Post_Operation : 2;
0072 } ScoreTqReqFlushPriority_Entry;
0073 
0074 /**
0075  * @brief Test context for spec:/score/tq/req/flush-priority test case.
0076  */
0077 typedef struct {
0078   /**
0079    * @brief This member contains the call within ISR request.
0080    */
0081   CallWithinISRRequest request;
0082 
0083   /**
0084    * @brief This member contains a copy of the corresponding
0085    *   ScoreTqReqFlushPriority_Run() parameter.
0086    */
0087   TQContext *tq_ctx;
0088 
0089   /**
0090    * @brief This member contains a copy of the corresponding
0091    *   ScoreTqReqFlushPriority_Run() parameter.
0092    */
0093   bool supports_multiple_priority_queues;
0094 
0095   struct {
0096     /**
0097      * @brief This member defines the pre-condition states for the next action.
0098      */
0099     size_t pcs[ 1 ];
0100 
0101     /**
0102      * @brief If this member is true, then the test action loop is executed.
0103      */
0104     bool in_action_loop;
0105 
0106     /**
0107      * @brief This member contains the next transition map index.
0108      */
0109     size_t index;
0110 
0111     /**
0112      * @brief This member contains the current transition map entry.
0113      */
0114     ScoreTqReqFlushPriority_Entry entry;
0115 
0116     /**
0117      * @brief If this member is true, then the current transition variant
0118      *   should be skipped.
0119      */
0120     bool skip;
0121   } Map;
0122 } ScoreTqReqFlushPriority_Context;
0123 
0124 static ScoreTqReqFlushPriority_Context
0125   ScoreTqReqFlushPriority_Instance;
0126 
0127 static const char * const ScoreTqReqFlushPriority_PreDesc_Queue[] = {
0128   "Empty",
0129   "NonEmpty",
0130   "NA"
0131 };
0132 
0133 static const char * const * const ScoreTqReqFlushPriority_PreDesc[] = {
0134   ScoreTqReqFlushPriority_PreDesc_Queue,
0135   NULL
0136 };
0137 
0138 typedef ScoreTqReqFlushPriority_Context Context;
0139 
0140 static const T_scheduler_event *GetUnblock( Context *ctx, size_t *index )
0141 {
0142   return TQGetNextUnblock( ctx->tq_ctx, index );
0143 }
0144 
0145 static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker )
0146 {
0147   return ctx->tq_ctx->worker_tcb[ worker ];
0148 }
0149 
0150 static void Flush( void *arg )
0151 {
0152   Context *ctx;
0153 
0154   ctx = arg;
0155   TQSchedulerRecordStart( ctx->tq_ctx );
0156   TQFlush( ctx->tq_ctx, true );
0157 }
0158 
0159 static void SchedulerEvent(
0160   void                    *arg,
0161   const T_scheduler_event *event,
0162   T_scheduler_when         when
0163 )
0164 {
0165   Context *ctx;
0166 
0167   ctx = arg;
0168 
0169   if (
0170     when == T_SCHEDULER_BEFORE &&
0171     event->operation == T_SCHEDULER_BLOCK
0172   ) {
0173     ctx->request.handler = Flush;
0174     ctx->request.arg = ctx;
0175     CallWithinISRSubmit( &ctx->request );
0176     T_scheduler_set_event_handler( NULL, NULL );
0177   }
0178 }
0179 
0180 static void ScoreTqReqFlushPriority_Pre_Queue_Prepare(
0181   ScoreTqReqFlushPriority_Context  *ctx,
0182   ScoreTqReqFlushPriority_Pre_Queue state
0183 )
0184 {
0185   switch ( state ) {
0186     case ScoreTqReqFlushPriority_Pre_Queue_Empty: {
0187       /*
0188        * While the thread queue is empty.
0189        */
0190       ctx->tq_ctx->how_many = 0;
0191       break;
0192     }
0193 
0194     case ScoreTqReqFlushPriority_Pre_Queue_NonEmpty: {
0195       /*
0196        * While the thread queue has at least one enqueued thread.
0197        */
0198       ctx->tq_ctx->how_many = 3;
0199       break;
0200     }
0201 
0202     case ScoreTqReqFlushPriority_Pre_Queue_NA:
0203       break;
0204   }
0205 }
0206 
0207 static void ScoreTqReqFlushPriority_Post_Operation_Check(
0208   ScoreTqReqFlushPriority_Context       *ctx,
0209   ScoreTqReqFlushPriority_Post_Operation state
0210 )
0211 {
0212   size_t                   i;
0213   const T_scheduler_event *event;
0214 
0215   i = 0;
0216 
0217   switch ( state ) {
0218     case ScoreTqReqFlushPriority_Post_Operation_Nop: {
0219       /*
0220        * No operation shall be performed.
0221        */
0222       /* Event receive */
0223       T_eq_ptr( GetUnblock( ctx, &i )->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
0224       T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null );
0225       break;
0226     }
0227 
0228     case ScoreTqReqFlushPriority_Post_Operation_TryExtract: {
0229       /*
0230        * The enqueued threads of the thread queue may be extracted in priority
0231        * order for each priority queue associated with a scheduler.  The
0232        * priority queues of the thread queue shall be accessed in FIFO order.
0233        */
0234       event = GetUnblock( ctx, &i );
0235       T_eq_ptr( event->executing, NULL );
0236       T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_D ) );
0237 
0238       event = GetUnblock( ctx, &i );
0239       T_eq_ptr( event->executing, NULL );
0240       T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_C ) );
0241 
0242       event = GetUnblock( ctx, &i );
0243       T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_B ) );
0244       T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_B ) );
0245 
0246       T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null );
0247       break;
0248     }
0249 
0250     case ScoreTqReqFlushPriority_Post_Operation_NA:
0251       break;
0252   }
0253 }
0254 
0255 static void ScoreTqReqFlushPriority_Setup(
0256   ScoreTqReqFlushPriority_Context *ctx
0257 )
0258 {
0259   TQReset( ctx->tq_ctx );
0260   TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_A, PRIO_ULTRA_HIGH );
0261 
0262   if (
0263     ctx->supports_multiple_priority_queues &&
0264     rtems_configuration_get_maximum_processors() > 1
0265   ) {
0266     TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_B, SCHEDULER_B_ID, PRIO_HIGH );
0267   } else {
0268     TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_B, PRIO_HIGH );
0269   }
0270 
0271   TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_C, PRIO_VERY_HIGH );
0272   TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_D, PRIO_ULTRA_HIGH );
0273 }
0274 
0275 static void ScoreTqReqFlushPriority_Setup_Wrap( void *arg )
0276 {
0277   ScoreTqReqFlushPriority_Context *ctx;
0278 
0279   ctx = arg;
0280   ctx->Map.in_action_loop = false;
0281   ScoreTqReqFlushPriority_Setup( ctx );
0282 }
0283 
0284 static void ScoreTqReqFlushPriority_Teardown(
0285   ScoreTqReqFlushPriority_Context *ctx
0286 )
0287 {
0288   TQReset( ctx->tq_ctx );
0289 }
0290 
0291 static void ScoreTqReqFlushPriority_Teardown_Wrap( void *arg )
0292 {
0293   ScoreTqReqFlushPriority_Context *ctx;
0294 
0295   ctx = arg;
0296   ctx->Map.in_action_loop = false;
0297   ScoreTqReqFlushPriority_Teardown( ctx );
0298 }
0299 
0300 static void ScoreTqReqFlushPriority_Action(
0301   ScoreTqReqFlushPriority_Context *ctx
0302 )
0303 {
0304   TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_PREPARE );
0305 
0306   if ( ctx->tq_ctx->how_many > 0 ) {
0307     TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE );
0308     TQSend( ctx->tq_ctx, TQ_BLOCKER_D, TQ_EVENT_ENQUEUE );
0309     T_scheduler_set_event_handler( SchedulerEvent, ctx );
0310     TQSendAndWaitForExecutionStop(
0311       ctx->tq_ctx,
0312       TQ_BLOCKER_B,
0313       TQ_EVENT_ENQUEUE
0314     );
0315   } else {
0316     TQSchedulerRecordStart( ctx->tq_ctx );
0317     TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL );
0318   }
0319 
0320   TQSchedulerRecordStop( ctx->tq_ctx );
0321   TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_DONE );
0322 }
0323 
0324 static const ScoreTqReqFlushPriority_Entry
0325 ScoreTqReqFlushPriority_Entries[] = {
0326   { 0, 0, ScoreTqReqFlushPriority_Post_Operation_Nop },
0327   { 0, 0, ScoreTqReqFlushPriority_Post_Operation_TryExtract }
0328 };
0329 
0330 static const uint8_t
0331 ScoreTqReqFlushPriority_Map[] = {
0332   0, 1
0333 };
0334 
0335 static size_t ScoreTqReqFlushPriority_Scope( void *arg, char *buf, size_t n )
0336 {
0337   ScoreTqReqFlushPriority_Context *ctx;
0338 
0339   ctx = arg;
0340 
0341   if ( ctx->Map.in_action_loop ) {
0342     return T_get_scope(
0343       ScoreTqReqFlushPriority_PreDesc,
0344       buf,
0345       n,
0346       ctx->Map.pcs
0347     );
0348   }
0349 
0350   return 0;
0351 }
0352 
0353 static T_fixture ScoreTqReqFlushPriority_Fixture = {
0354   .setup = ScoreTqReqFlushPriority_Setup_Wrap,
0355   .stop = NULL,
0356   .teardown = ScoreTqReqFlushPriority_Teardown_Wrap,
0357   .scope = ScoreTqReqFlushPriority_Scope,
0358   .initial_context = &ScoreTqReqFlushPriority_Instance
0359 };
0360 
0361 static inline ScoreTqReqFlushPriority_Entry ScoreTqReqFlushPriority_PopEntry(
0362   ScoreTqReqFlushPriority_Context *ctx
0363 )
0364 {
0365   size_t index;
0366 
0367   index = ctx->Map.index;
0368   ctx->Map.index = index + 1;
0369   return ScoreTqReqFlushPriority_Entries[
0370     ScoreTqReqFlushPriority_Map[ index ]
0371   ];
0372 }
0373 
0374 static void ScoreTqReqFlushPriority_TestVariant(
0375   ScoreTqReqFlushPriority_Context *ctx
0376 )
0377 {
0378   ScoreTqReqFlushPriority_Pre_Queue_Prepare( ctx, ctx->Map.pcs[ 0 ] );
0379   ScoreTqReqFlushPriority_Action( ctx );
0380   ScoreTqReqFlushPriority_Post_Operation_Check(
0381     ctx,
0382     ctx->Map.entry.Post_Operation
0383   );
0384 }
0385 
0386 static T_fixture_node ScoreTqReqFlushPriority_Node;
0387 
0388 static T_remark ScoreTqReqFlushPriority_Remark = {
0389   .next = NULL,
0390   .remark = "ScoreTqReqFlushPriority"
0391 };
0392 
0393 void ScoreTqReqFlushPriority_Run(
0394   TQContext *tq_ctx,
0395   bool       supports_multiple_priority_queues
0396 )
0397 {
0398   ScoreTqReqFlushPriority_Context *ctx;
0399 
0400   ctx = &ScoreTqReqFlushPriority_Instance;
0401   ctx->tq_ctx = tq_ctx;
0402   ctx->supports_multiple_priority_queues = supports_multiple_priority_queues;
0403 
0404   ctx = T_push_fixture(
0405     &ScoreTqReqFlushPriority_Node,
0406     &ScoreTqReqFlushPriority_Fixture
0407   );
0408   ctx->Map.in_action_loop = true;
0409   ctx->Map.index = 0;
0410 
0411   for (
0412     ctx->Map.pcs[ 0 ] = ScoreTqReqFlushPriority_Pre_Queue_Empty;
0413     ctx->Map.pcs[ 0 ] < ScoreTqReqFlushPriority_Pre_Queue_NA;
0414     ++ctx->Map.pcs[ 0 ]
0415   ) {
0416     ctx->Map.entry = ScoreTqReqFlushPriority_PopEntry( ctx );
0417     ScoreTqReqFlushPriority_TestVariant( ctx );
0418   }
0419 
0420   T_add_remark( &ScoreTqReqFlushPriority_Remark );
0421   T_pop_fixture();
0422 }
0423 
0424 /** @} */