File indexing completed on 2025-05-11 08:24:53
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
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
0062
0063
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
0076
0077 typedef struct {
0078
0079
0080
0081 CallWithinISRRequest request;
0082
0083
0084
0085
0086
0087 TQContext *tq_ctx;
0088
0089
0090
0091
0092
0093 bool supports_multiple_priority_queues;
0094
0095 struct {
0096
0097
0098
0099 size_t pcs[ 1 ];
0100
0101
0102
0103
0104 bool in_action_loop;
0105
0106
0107
0108
0109 size_t index;
0110
0111
0112
0113
0114 ScoreTqReqFlushPriority_Entry entry;
0115
0116
0117
0118
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
0189
0190 ctx->tq_ctx->how_many = 0;
0191 break;
0192 }
0193
0194 case ScoreTqReqFlushPriority_Pre_Queue_NonEmpty: {
0195
0196
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
0221
0222
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
0231
0232
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