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-fifo.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_MayStop_NA : 1;
0071 uint8_t Pre_QueueEmpty_NA : 1;
0072 uint8_t Pre_Stop_NA : 1;
0073 uint8_t Pre_WaitState_NA : 1;
0074 uint8_t Post_Operation : 2;
0075 } ScoreTqReqFlushFifo_Entry;
0076
0077
0078
0079
0080 typedef struct {
0081
0082
0083
0084 bool stop;
0085
0086
0087
0088
0089
0090 bool intend_to_block;
0091
0092
0093
0094
0095 CallWithinISRRequest request;
0096
0097
0098
0099
0100
0101 TQContext *tq_ctx;
0102
0103
0104
0105
0106
0107 bool may_stop;
0108
0109 struct {
0110
0111
0112
0113
0114 size_t pci[ 4 ];
0115
0116
0117
0118
0119 size_t pcs[ 4 ];
0120
0121
0122
0123
0124 bool in_action_loop;
0125
0126
0127
0128
0129 size_t index;
0130
0131
0132
0133
0134 ScoreTqReqFlushFifo_Entry entry;
0135
0136
0137
0138
0139
0140 bool skip;
0141 } Map;
0142 } ScoreTqReqFlushFifo_Context;
0143
0144 static ScoreTqReqFlushFifo_Context
0145 ScoreTqReqFlushFifo_Instance;
0146
0147 static const char * const ScoreTqReqFlushFifo_PreDesc_MayStop[] = {
0148 "Yes",
0149 "No",
0150 "NA"
0151 };
0152
0153 static const char * const ScoreTqReqFlushFifo_PreDesc_QueueEmpty[] = {
0154 "Yes",
0155 "No",
0156 "NA"
0157 };
0158
0159 static const char * const ScoreTqReqFlushFifo_PreDesc_Stop[] = {
0160 "Yes",
0161 "No",
0162 "NA"
0163 };
0164
0165 static const char * const ScoreTqReqFlushFifo_PreDesc_WaitState[] = {
0166 "Blocked",
0167 "IntendToBlock",
0168 "NA"
0169 };
0170
0171 static const char * const * const ScoreTqReqFlushFifo_PreDesc[] = {
0172 ScoreTqReqFlushFifo_PreDesc_MayStop,
0173 ScoreTqReqFlushFifo_PreDesc_QueueEmpty,
0174 ScoreTqReqFlushFifo_PreDesc_Stop,
0175 ScoreTqReqFlushFifo_PreDesc_WaitState,
0176 NULL
0177 };
0178
0179 typedef ScoreTqReqFlushFifo_Context Context;
0180
0181 static const T_scheduler_event *GetUnblock( Context *ctx, size_t *index )
0182 {
0183 return TQGetNextUnblock( ctx->tq_ctx, index );
0184 }
0185
0186 static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker )
0187 {
0188 return ctx->tq_ctx->worker_tcb[ worker ];
0189 }
0190
0191 static void BlockerAFlush( Context *ctx )
0192 {
0193 TQSchedulerRecordStart( ctx->tq_ctx );
0194
0195 if ( ctx->stop ) {
0196 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_PARTIAL );
0197 } else {
0198 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL );
0199 }
0200 }
0201
0202 static void InterruptFlush( void *arg )
0203 {
0204 Context *ctx;
0205
0206 ctx = arg;
0207 TQSchedulerRecordStart( ctx->tq_ctx );
0208 TQFlush( ctx->tq_ctx, !ctx->stop );
0209 }
0210
0211 static void SchedulerEvent(
0212 void *arg,
0213 const T_scheduler_event *event,
0214 T_scheduler_when when
0215 )
0216 {
0217 Context *ctx;
0218
0219 ctx = arg;
0220
0221 if (
0222 when == T_SCHEDULER_BEFORE &&
0223 event->operation == T_SCHEDULER_BLOCK
0224 ) {
0225 T_scheduler_set_event_handler( NULL, NULL );
0226 ctx->request.handler = InterruptFlush;
0227 CallWithinISRSubmit( &ctx->request );
0228 }
0229 }
0230
0231 static uint32_t CheckExtractions( Context *ctx )
0232 {
0233 uint32_t extracted_threads;
0234 size_t i;
0235 const T_scheduler_event *event;
0236
0237 extracted_threads = 0;
0238 i = 0;
0239
0240 if ( !ctx->intend_to_block ) {
0241
0242 T_eq_ptr( GetUnblock( ctx, &i )->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
0243 }
0244
0245 event = GetUnblock( ctx, &i );
0246
0247 if ( event != &T_scheduler_event_null ) {
0248 if ( ctx->intend_to_block ) {
0249 T_eq_ptr( event->executing, NULL );
0250 } else {
0251 T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_A ) );
0252 }
0253
0254 T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_B ) );
0255 ++extracted_threads;
0256 }
0257
0258 event = GetUnblock( ctx, &i );
0259
0260 if ( event != &T_scheduler_event_null ) {
0261 if ( ctx->intend_to_block ) {
0262 T_eq_ptr( event->executing, NULL );
0263 } else {
0264 T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_A ) );
0265 }
0266
0267 T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_C ) );
0268 ++extracted_threads;
0269 }
0270
0271 event = GetUnblock( ctx, &i );
0272
0273 if ( event != &T_scheduler_event_null ) {
0274 if ( ctx->intend_to_block ) {
0275 T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_D ) );
0276 } else {
0277 T_eq_ptr( event->executing, GetTCB( ctx, TQ_BLOCKER_A ) );
0278 }
0279
0280 T_eq_ptr( event->thread, GetTCB( ctx, TQ_BLOCKER_D ) );
0281 ++extracted_threads;
0282 }
0283
0284 T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null );
0285 T_eq_u32( extracted_threads, ctx->tq_ctx->flush_count );
0286
0287 return extracted_threads;
0288 }
0289
0290 static void ScoreTqReqFlushFifo_Pre_MayStop_Prepare(
0291 ScoreTqReqFlushFifo_Context *ctx,
0292 ScoreTqReqFlushFifo_Pre_MayStop state
0293 )
0294 {
0295 switch ( state ) {
0296 case ScoreTqReqFlushFifo_Pre_MayStop_Yes: {
0297
0298
0299
0300 if ( !ctx->may_stop ) {
0301 ctx->Map.skip = true;
0302 }
0303 break;
0304 }
0305
0306 case ScoreTqReqFlushFifo_Pre_MayStop_No: {
0307
0308
0309
0310 if ( ctx->may_stop ) {
0311 ctx->Map.skip = true;
0312 }
0313 break;
0314 }
0315
0316 case ScoreTqReqFlushFifo_Pre_MayStop_NA:
0317 break;
0318 }
0319 }
0320
0321 static void ScoreTqReqFlushFifo_Pre_QueueEmpty_Prepare(
0322 ScoreTqReqFlushFifo_Context *ctx,
0323 ScoreTqReqFlushFifo_Pre_QueueEmpty state
0324 )
0325 {
0326 switch ( state ) {
0327 case ScoreTqReqFlushFifo_Pre_QueueEmpty_Yes: {
0328
0329
0330
0331 ctx->tq_ctx->how_many = 0;
0332 break;
0333 }
0334
0335 case ScoreTqReqFlushFifo_Pre_QueueEmpty_No: {
0336
0337
0338
0339 ctx->tq_ctx->how_many = 3;
0340 break;
0341 }
0342
0343 case ScoreTqReqFlushFifo_Pre_QueueEmpty_NA:
0344 break;
0345 }
0346 }
0347
0348 static void ScoreTqReqFlushFifo_Pre_Stop_Prepare(
0349 ScoreTqReqFlushFifo_Context *ctx,
0350 ScoreTqReqFlushFifo_Pre_Stop state
0351 )
0352 {
0353 switch ( state ) {
0354 case ScoreTqReqFlushFifo_Pre_Stop_Yes: {
0355
0356
0357
0358 ctx->stop = true;
0359 break;
0360 }
0361
0362 case ScoreTqReqFlushFifo_Pre_Stop_No: {
0363
0364
0365
0366 ctx->stop = false;
0367 break;
0368 }
0369
0370 case ScoreTqReqFlushFifo_Pre_Stop_NA:
0371 break;
0372 }
0373 }
0374
0375 static void ScoreTqReqFlushFifo_Pre_WaitState_Prepare(
0376 ScoreTqReqFlushFifo_Context *ctx,
0377 ScoreTqReqFlushFifo_Pre_WaitState state
0378 )
0379 {
0380 switch ( state ) {
0381 case ScoreTqReqFlushFifo_Pre_WaitState_Blocked: {
0382
0383
0384
0385
0386 ctx->intend_to_block = false;
0387 break;
0388 }
0389
0390 case ScoreTqReqFlushFifo_Pre_WaitState_IntendToBlock: {
0391
0392
0393
0394
0395 ctx->intend_to_block = true;
0396 break;
0397 }
0398
0399 case ScoreTqReqFlushFifo_Pre_WaitState_NA:
0400 break;
0401 }
0402 }
0403
0404 static void ScoreTqReqFlushFifo_Post_Operation_Check(
0405 ScoreTqReqFlushFifo_Context *ctx,
0406 ScoreTqReqFlushFifo_Post_Operation state
0407 )
0408 {
0409 size_t i;
0410 uint32_t extracted_threads;
0411
0412 switch ( state ) {
0413 case ScoreTqReqFlushFifo_Post_Operation_Nop: {
0414
0415
0416
0417
0418 i = 0;
0419 T_eq_ptr( GetUnblock( ctx, &i )->thread, GetTCB( ctx, TQ_BLOCKER_A ) );
0420 T_eq_ptr( GetUnblock( ctx, &i ), &T_scheduler_event_null );
0421 break;
0422 }
0423
0424 case ScoreTqReqFlushFifo_Post_Operation_ExtractAll: {
0425
0426
0427
0428
0429 extracted_threads = CheckExtractions( ctx );
0430 T_eq_sz( extracted_threads, ctx->tq_ctx->how_many );
0431 break;
0432 }
0433
0434 case ScoreTqReqFlushFifo_Post_Operation_ExtractPartial: {
0435
0436
0437
0438
0439
0440 extracted_threads = CheckExtractions( ctx );
0441 T_lt_sz( extracted_threads, ctx->tq_ctx->how_many );
0442 break;
0443 }
0444
0445 case ScoreTqReqFlushFifo_Post_Operation_NA:
0446 break;
0447 }
0448 }
0449
0450 static void ScoreTqReqFlushFifo_Setup( ScoreTqReqFlushFifo_Context *ctx )
0451 {
0452 ctx->request.arg = ctx;
0453 TQReset( ctx->tq_ctx );
0454 TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_A, PRIO_ULTRA_HIGH );
0455 TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_B, PRIO_VERY_HIGH );
0456 TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_C, PRIO_HIGH );
0457 TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_D, PRIO_HIGH );
0458 }
0459
0460 static void ScoreTqReqFlushFifo_Setup_Wrap( void *arg )
0461 {
0462 ScoreTqReqFlushFifo_Context *ctx;
0463
0464 ctx = arg;
0465 ctx->Map.in_action_loop = false;
0466 ScoreTqReqFlushFifo_Setup( ctx );
0467 }
0468
0469 static void ScoreTqReqFlushFifo_Teardown( ScoreTqReqFlushFifo_Context *ctx )
0470 {
0471 TQReset( ctx->tq_ctx );
0472 }
0473
0474 static void ScoreTqReqFlushFifo_Teardown_Wrap( void *arg )
0475 {
0476 ScoreTqReqFlushFifo_Context *ctx;
0477
0478 ctx = arg;
0479 ctx->Map.in_action_loop = false;
0480 ScoreTqReqFlushFifo_Teardown( ctx );
0481 }
0482
0483 static void ScoreTqReqFlushFifo_Action( ScoreTqReqFlushFifo_Context *ctx )
0484 {
0485 uint32_t flush_count;
0486
0487 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_PREPARE );
0488
0489 if ( ctx->tq_ctx->how_many > 0 ) {
0490 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_ENQUEUE );
0491 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE );
0492
0493 if ( ctx->intend_to_block ) {
0494 T_scheduler_set_event_handler( SchedulerEvent, ctx );
0495 }
0496
0497 TQSend( ctx->tq_ctx, TQ_BLOCKER_D, TQ_EVENT_ENQUEUE );
0498
0499 if ( !ctx->intend_to_block ) {
0500 BlockerAFlush( ctx );
0501 }
0502 } else {
0503 BlockerAFlush( ctx );
0504 }
0505
0506 flush_count = ctx->tq_ctx->flush_count;
0507 TQSchedulerRecordStop( ctx->tq_ctx );
0508 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_FLUSH_ALL );
0509 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE_DONE );
0510 ctx->tq_ctx->flush_count = flush_count;
0511 }
0512
0513 static const ScoreTqReqFlushFifo_Entry
0514 ScoreTqReqFlushFifo_Entries[] = {
0515 { 0, 0, 0, 1, 1, ScoreTqReqFlushFifo_Post_Operation_Nop },
0516 { 0, 0, 0, 0, 0, ScoreTqReqFlushFifo_Post_Operation_ExtractAll },
0517 { 0, 0, 0, 0, 0, ScoreTqReqFlushFifo_Post_Operation_ExtractPartial },
0518 { 1, 0, 0, 0, 0, ScoreTqReqFlushFifo_Post_Operation_NA }
0519 };
0520
0521 static const uint8_t
0522 ScoreTqReqFlushFifo_Map[] = {
0523 0, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0, 0, 3, 3, 1, 1
0524 };
0525
0526 static size_t ScoreTqReqFlushFifo_Scope( void *arg, char *buf, size_t n )
0527 {
0528 ScoreTqReqFlushFifo_Context *ctx;
0529
0530 ctx = arg;
0531
0532 if ( ctx->Map.in_action_loop ) {
0533 return T_get_scope( ScoreTqReqFlushFifo_PreDesc, buf, n, ctx->Map.pcs );
0534 }
0535
0536 return 0;
0537 }
0538
0539 static T_fixture ScoreTqReqFlushFifo_Fixture = {
0540 .setup = ScoreTqReqFlushFifo_Setup_Wrap,
0541 .stop = NULL,
0542 .teardown = ScoreTqReqFlushFifo_Teardown_Wrap,
0543 .scope = ScoreTqReqFlushFifo_Scope,
0544 .initial_context = &ScoreTqReqFlushFifo_Instance
0545 };
0546
0547 static const uint8_t ScoreTqReqFlushFifo_Weights[] = {
0548 8, 4, 2, 1
0549 };
0550
0551 static void ScoreTqReqFlushFifo_Skip(
0552 ScoreTqReqFlushFifo_Context *ctx,
0553 size_t index
0554 )
0555 {
0556 switch ( index + 1 ) {
0557 case 1:
0558 ctx->Map.pci[ 1 ] = ScoreTqReqFlushFifo_Pre_QueueEmpty_NA - 1;
0559
0560 case 2:
0561 ctx->Map.pci[ 2 ] = ScoreTqReqFlushFifo_Pre_Stop_NA - 1;
0562
0563 case 3:
0564 ctx->Map.pci[ 3 ] = ScoreTqReqFlushFifo_Pre_WaitState_NA - 1;
0565 break;
0566 }
0567 }
0568
0569 static inline ScoreTqReqFlushFifo_Entry ScoreTqReqFlushFifo_PopEntry(
0570 ScoreTqReqFlushFifo_Context *ctx
0571 )
0572 {
0573 size_t index;
0574
0575 if ( ctx->Map.skip ) {
0576 size_t i;
0577
0578 ctx->Map.skip = false;
0579 index = 0;
0580
0581 for ( i = 0; i < 4; ++i ) {
0582 index += ScoreTqReqFlushFifo_Weights[ i ] * ctx->Map.pci[ i ];
0583 }
0584 } else {
0585 index = ctx->Map.index;
0586 }
0587
0588 ctx->Map.index = index + 1;
0589
0590 return ScoreTqReqFlushFifo_Entries[
0591 ScoreTqReqFlushFifo_Map[ index ]
0592 ];
0593 }
0594
0595 static void ScoreTqReqFlushFifo_SetPreConditionStates(
0596 ScoreTqReqFlushFifo_Context *ctx
0597 )
0598 {
0599 ctx->Map.pcs[ 0 ] = ctx->Map.pci[ 0 ];
0600 ctx->Map.pcs[ 1 ] = ctx->Map.pci[ 1 ];
0601
0602 if ( ctx->Map.entry.Pre_Stop_NA ) {
0603 ctx->Map.pcs[ 2 ] = ScoreTqReqFlushFifo_Pre_Stop_NA;
0604 } else {
0605 ctx->Map.pcs[ 2 ] = ctx->Map.pci[ 2 ];
0606 }
0607
0608 if ( ctx->Map.entry.Pre_WaitState_NA ) {
0609 ctx->Map.pcs[ 3 ] = ScoreTqReqFlushFifo_Pre_WaitState_NA;
0610 } else {
0611 ctx->Map.pcs[ 3 ] = ctx->Map.pci[ 3 ];
0612 }
0613 }
0614
0615 static void ScoreTqReqFlushFifo_TestVariant( ScoreTqReqFlushFifo_Context *ctx )
0616 {
0617 ScoreTqReqFlushFifo_Pre_MayStop_Prepare( ctx, ctx->Map.pcs[ 0 ] );
0618
0619 if ( ctx->Map.skip ) {
0620 ScoreTqReqFlushFifo_Skip( ctx, 0 );
0621 return;
0622 }
0623
0624 ScoreTqReqFlushFifo_Pre_QueueEmpty_Prepare( ctx, ctx->Map.pcs[ 1 ] );
0625 ScoreTqReqFlushFifo_Pre_Stop_Prepare( ctx, ctx->Map.pcs[ 2 ] );
0626 ScoreTqReqFlushFifo_Pre_WaitState_Prepare( ctx, ctx->Map.pcs[ 3 ] );
0627 ScoreTqReqFlushFifo_Action( ctx );
0628 ScoreTqReqFlushFifo_Post_Operation_Check(
0629 ctx,
0630 ctx->Map.entry.Post_Operation
0631 );
0632 }
0633
0634 static T_fixture_node ScoreTqReqFlushFifo_Node;
0635
0636 static T_remark ScoreTqReqFlushFifo_Remark = {
0637 .next = NULL,
0638 .remark = "ScoreTqReqFlushFifo"
0639 };
0640
0641 void ScoreTqReqFlushFifo_Run( TQContext *tq_ctx, bool may_stop )
0642 {
0643 ScoreTqReqFlushFifo_Context *ctx;
0644
0645 ctx = &ScoreTqReqFlushFifo_Instance;
0646 ctx->tq_ctx = tq_ctx;
0647 ctx->may_stop = may_stop;
0648
0649 ctx = T_push_fixture(
0650 &ScoreTqReqFlushFifo_Node,
0651 &ScoreTqReqFlushFifo_Fixture
0652 );
0653 ctx->Map.in_action_loop = true;
0654 ctx->Map.index = 0;
0655 ctx->Map.skip = false;
0656
0657 for (
0658 ctx->Map.pci[ 0 ] = ScoreTqReqFlushFifo_Pre_MayStop_Yes;
0659 ctx->Map.pci[ 0 ] < ScoreTqReqFlushFifo_Pre_MayStop_NA;
0660 ++ctx->Map.pci[ 0 ]
0661 ) {
0662 for (
0663 ctx->Map.pci[ 1 ] = ScoreTqReqFlushFifo_Pre_QueueEmpty_Yes;
0664 ctx->Map.pci[ 1 ] < ScoreTqReqFlushFifo_Pre_QueueEmpty_NA;
0665 ++ctx->Map.pci[ 1 ]
0666 ) {
0667 for (
0668 ctx->Map.pci[ 2 ] = ScoreTqReqFlushFifo_Pre_Stop_Yes;
0669 ctx->Map.pci[ 2 ] < ScoreTqReqFlushFifo_Pre_Stop_NA;
0670 ++ctx->Map.pci[ 2 ]
0671 ) {
0672 for (
0673 ctx->Map.pci[ 3 ] = ScoreTqReqFlushFifo_Pre_WaitState_Blocked;
0674 ctx->Map.pci[ 3 ] < ScoreTqReqFlushFifo_Pre_WaitState_NA;
0675 ++ctx->Map.pci[ 3 ]
0676 ) {
0677 ctx->Map.entry = ScoreTqReqFlushFifo_PopEntry( ctx );
0678
0679 if ( ctx->Map.entry.Skip ) {
0680 continue;
0681 }
0682
0683 ScoreTqReqFlushFifo_SetPreConditionStates( ctx );
0684 ScoreTqReqFlushFifo_TestVariant( ctx );
0685 }
0686 }
0687 }
0688 }
0689
0690 T_add_remark( &ScoreTqReqFlushFifo_Remark );
0691 T_pop_fixture();
0692 }
0693
0694