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-enqueue-ceiling.h"
0056
0057 #include <rtems/test.h>
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 typedef struct {
0068 uint8_t Skip : 1;
0069 uint8_t Pre_EligibleScheduler_NA : 1;
0070 uint8_t Pre_QueueEligible_NA : 1;
0071 uint8_t Pre_QueueIneligible_NA : 1;
0072 uint8_t Post_Position : 3;
0073 } ScoreTqReqEnqueueCeiling_Entry;
0074
0075
0076
0077
0078 typedef struct {
0079
0080
0081
0082
0083 bool helping;
0084
0085
0086
0087
0088
0089 rtems_task_priority priority;
0090
0091
0092
0093
0094
0095
0096
0097 size_t other_before;
0098
0099
0100
0101
0102
0103
0104
0105 size_t other_after;
0106
0107
0108
0109
0110
0111 TQContext *tq_ctx;
0112
0113 struct {
0114
0115
0116
0117 size_t pcs[ 3 ];
0118
0119
0120
0121
0122 bool in_action_loop;
0123
0124
0125
0126
0127 size_t index;
0128
0129
0130
0131
0132 ScoreTqReqEnqueueCeiling_Entry entry;
0133
0134
0135
0136
0137
0138 bool skip;
0139 } Map;
0140 } ScoreTqReqEnqueueCeiling_Context;
0141
0142 static ScoreTqReqEnqueueCeiling_Context
0143 ScoreTqReqEnqueueCeiling_Instance;
0144
0145 static const char * const ScoreTqReqEnqueueCeiling_PreDesc_EligibleScheduler[] = {
0146 "Home",
0147 "Helping",
0148 "NA"
0149 };
0150
0151 static const char * const ScoreTqReqEnqueueCeiling_PreDesc_QueueEligible[] = {
0152 "None",
0153 "Equal",
0154 "Low",
0155 "NA"
0156 };
0157
0158 static const char * const ScoreTqReqEnqueueCeiling_PreDesc_QueueIneligible[] = {
0159 "None",
0160 "Before",
0161 "After",
0162 "NA"
0163 };
0164
0165 static const char * const * const ScoreTqReqEnqueueCeiling_PreDesc[] = {
0166 ScoreTqReqEnqueueCeiling_PreDesc_EligibleScheduler,
0167 ScoreTqReqEnqueueCeiling_PreDesc_QueueEligible,
0168 ScoreTqReqEnqueueCeiling_PreDesc_QueueIneligible,
0169 NULL
0170 };
0171
0172 typedef ScoreTqReqEnqueueCeiling_Context Context;
0173
0174 static const rtems_tcb *GetUnblock( Context *ctx, size_t *index )
0175 {
0176 const rtems_tcb *thread;
0177
0178 do {
0179 thread = TQGetNextUnblock( ctx->tq_ctx, index )->thread;
0180 } while ( thread == ctx->tq_ctx->runner_tcb );
0181
0182 return thread;
0183 }
0184
0185 static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker )
0186 {
0187 return ctx->tq_ctx->worker_tcb[ worker ];
0188 }
0189
0190 static void AddHelper( TQContext *tq_ctx, rtems_id scheduler_id )
0191 {
0192 TQSend( tq_ctx, TQ_BLOCKER_C, TQ_EVENT_MUTEX_A_OBTAIN );
0193 TQSetScheduler( tq_ctx, TQ_BLOCKER_E, scheduler_id, PRIO_LOW );
0194 TQSendAndWaitForExecutionStop(
0195 tq_ctx,
0196 TQ_BLOCKER_E,
0197 TQ_EVENT_MUTEX_A_OBTAIN | TQ_EVENT_MUTEX_A_RELEASE
0198 );
0199 }
0200
0201 static void RemoveHelper( TQContext *tq_ctx )
0202 {
0203 TQSend( tq_ctx, TQ_BLOCKER_C, TQ_EVENT_MUTEX_A_RELEASE );
0204 TQMutexObtain( tq_ctx, TQ_MUTEX_A );
0205 TQMutexRelease( tq_ctx, TQ_MUTEX_A );
0206 }
0207
0208 static void ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_Prepare(
0209 ScoreTqReqEnqueueCeiling_Context *ctx,
0210 ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler state
0211 )
0212 {
0213 switch ( state ) {
0214 case ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_Home: {
0215
0216
0217
0218 ctx->helping = false;
0219 break;
0220 }
0221
0222 case ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_Helping: {
0223
0224
0225
0226 ctx->helping = true;
0227 break;
0228 }
0229
0230 case ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_NA:
0231 break;
0232 }
0233 }
0234
0235 static void ScoreTqReqEnqueueCeiling_Pre_QueueEligible_Prepare(
0236 ScoreTqReqEnqueueCeiling_Context *ctx,
0237 ScoreTqReqEnqueueCeiling_Pre_QueueEligible state
0238 )
0239 {
0240 switch ( state ) {
0241 case ScoreTqReqEnqueueCeiling_Pre_QueueEligible_None: {
0242
0243
0244
0245
0246
0247 break;
0248 }
0249
0250 case ScoreTqReqEnqueueCeiling_Pre_QueueEligible_Equal: {
0251
0252
0253
0254
0255
0256
0257 ctx->priority = PRIO_VERY_HIGH;
0258 break;
0259 }
0260
0261 case ScoreTqReqEnqueueCeiling_Pre_QueueEligible_Low: {
0262
0263
0264
0265
0266
0267
0268 ctx->priority = PRIO_HIGH;
0269 break;
0270 }
0271
0272 case ScoreTqReqEnqueueCeiling_Pre_QueueEligible_NA:
0273 break;
0274 }
0275 }
0276
0277 static void ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_Prepare(
0278 ScoreTqReqEnqueueCeiling_Context *ctx,
0279 ScoreTqReqEnqueueCeiling_Pre_QueueIneligible state
0280 )
0281 {
0282 switch ( state ) {
0283 case ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_None: {
0284
0285
0286
0287
0288
0289 break;
0290 }
0291
0292 case ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_Before: {
0293
0294
0295
0296
0297
0298
0299 ctx->other_before = true;
0300 break;
0301 }
0302
0303 case ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_After: {
0304
0305
0306
0307
0308
0309
0310 ctx->other_after = true;
0311 break;
0312 }
0313
0314 case ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_NA:
0315 break;
0316 }
0317 }
0318
0319 static void ScoreTqReqEnqueueCeiling_Post_Position_Check(
0320 ScoreTqReqEnqueueCeiling_Context *ctx,
0321 ScoreTqReqEnqueueCeiling_Post_Position state
0322 )
0323 {
0324 size_t i;
0325
0326 i = 0;
0327
0328
0329 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0330 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_A ) );
0331
0332 switch ( state ) {
0333 case ScoreTqReqEnqueueCeiling_Post_Position_InitialFirst: {
0334
0335
0336
0337
0338
0339 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0340 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0341 break;
0342 }
0343
0344 case ScoreTqReqEnqueueCeiling_Post_Position_First: {
0345
0346
0347
0348
0349 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0350 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_B ) );
0351 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0352 break;
0353 }
0354
0355 case ScoreTqReqEnqueueCeiling_Post_Position_Second: {
0356
0357
0358
0359
0360 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_B ) );
0361 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0362 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0363 break;
0364 }
0365
0366 case ScoreTqReqEnqueueCeiling_Post_Position_FirstFirst: {
0367
0368
0369
0370
0371
0372
0373
0374 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0375 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_B ) );
0376 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0377 break;
0378 }
0379
0380 case ScoreTqReqEnqueueCeiling_Post_Position_SecondFirst: {
0381
0382
0383
0384
0385
0386
0387
0388 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_B ) );
0389 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0390 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0391 break;
0392 }
0393
0394 case ScoreTqReqEnqueueCeiling_Post_Position_SecondQueue: {
0395
0396
0397
0398
0399
0400
0401
0402 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_B ) );
0403 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_C ) );
0404 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0405 break;
0406 }
0407
0408 case ScoreTqReqEnqueueCeiling_Post_Position_NA:
0409 break;
0410 }
0411 }
0412
0413 static void ScoreTqReqEnqueueCeiling_Setup(
0414 ScoreTqReqEnqueueCeiling_Context *ctx
0415 )
0416 {
0417 rtems_id scheduler_id;
0418
0419 scheduler_id = SCHEDULER_A_ID;
0420 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_A, scheduler_id, PRIO_VERY_HIGH );
0421 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_B, scheduler_id, PRIO_VERY_HIGH );
0422 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_C, scheduler_id, PRIO_VERY_HIGH );
0423 #if defined( RTEMS_SMP )
0424 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_D, SCHEDULER_B_ID, PRIO_LOW );
0425 #endif
0426 }
0427
0428 static void ScoreTqReqEnqueueCeiling_Setup_Wrap( void *arg )
0429 {
0430 ScoreTqReqEnqueueCeiling_Context *ctx;
0431
0432 ctx = arg;
0433 ctx->Map.in_action_loop = false;
0434 ScoreTqReqEnqueueCeiling_Setup( ctx );
0435 }
0436
0437 static void ScoreTqReqEnqueueCeiling_Teardown(
0438 ScoreTqReqEnqueueCeiling_Context *ctx
0439 )
0440 {
0441 TQReset( ctx->tq_ctx );
0442 }
0443
0444 static void ScoreTqReqEnqueueCeiling_Teardown_Wrap( void *arg )
0445 {
0446 ScoreTqReqEnqueueCeiling_Context *ctx;
0447
0448 ctx = arg;
0449 ctx->Map.in_action_loop = false;
0450 ScoreTqReqEnqueueCeiling_Teardown( ctx );
0451 }
0452
0453 static void ScoreTqReqEnqueueCeiling_Prepare(
0454 ScoreTqReqEnqueueCeiling_Context *ctx
0455 )
0456 {
0457 ctx->priority = PRIO_PSEUDO_ISR;
0458 ctx->other_before = false;
0459 ctx->other_after = false;
0460 }
0461
0462 static void ScoreTqReqEnqueueCeiling_Action(
0463 ScoreTqReqEnqueueCeiling_Context *ctx
0464 )
0465 {
0466 Status_Control status;
0467
0468 if ( ctx->priority == PRIO_PSEUDO_ISR ) {
0469 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0470 } else {
0471 TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_B , ctx->priority );
0472
0473 if ( ctx->other_before || ctx->other_after ) {
0474 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_MUTEX_B_OBTAIN );
0475 TQSendAndWaitForExecutionStop(
0476 ctx->tq_ctx,
0477 TQ_BLOCKER_D,
0478 TQ_EVENT_MUTEX_B_OBTAIN | TQ_EVENT_MUTEX_B_RELEASE |
0479 TQ_EVENT_RUNNER_SYNC
0480 );
0481
0482 if ( ctx->other_before ) {
0483 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE );
0484 }
0485
0486 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0487 TQSend(
0488 ctx->tq_ctx,
0489 TQ_BLOCKER_B,
0490 TQ_EVENT_ENQUEUE | TQ_EVENT_SURRENDER
0491 );
0492
0493 if ( ctx->other_before ) {
0494 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_SURRENDER );
0495 }
0496 } else {
0497 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0498 TQSend(
0499 ctx->tq_ctx,
0500 TQ_BLOCKER_B,
0501 TQ_EVENT_ENQUEUE | TQ_EVENT_SURRENDER
0502 );
0503 }
0504 }
0505
0506 if ( ctx->helping ) {
0507 if ( ctx->other_before || ctx->other_after ) {
0508 if ( rtems_scheduler_get_processor_maximum() > 2 ) {
0509 AddHelper( ctx->tq_ctx, SCHEDULER_C_ID );
0510 }
0511 } else {
0512 AddHelper( ctx->tq_ctx, SCHEDULER_B_ID );
0513 }
0514 }
0515
0516 TQSchedulerRecordStart( ctx->tq_ctx );
0517 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_ENQUEUE | TQ_EVENT_SURRENDER );
0518 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_SURRENDER );
0519 status = TQEnqueue( ctx->tq_ctx, TQ_WAIT_FOREVER );
0520 T_eq_int( status, TQConvertStatus( ctx->tq_ctx, STATUS_SUCCESSFUL ) );
0521 TQSchedulerRecordStop( ctx->tq_ctx );
0522 status = TQSurrender( ctx->tq_ctx );
0523 T_eq_int( status, TQConvertStatus( ctx->tq_ctx, STATUS_SUCCESSFUL ) );
0524
0525 if (
0526 ctx->priority != PRIO_PSEUDO_ISR &&
0527 ( ctx->other_before || ctx->other_after )
0528 ) {
0529 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_MUTEX_B_RELEASE );
0530 TQSynchronizeRunner();
0531 }
0532
0533 if ( ctx->helping ) {
0534 if ( ctx->other_before || ctx->other_after ) {
0535 if ( rtems_scheduler_get_processor_maximum() > 2 ) {
0536 RemoveHelper( ctx->tq_ctx );
0537 }
0538 } else {
0539 RemoveHelper( ctx->tq_ctx );
0540 }
0541 }
0542 }
0543
0544 static const ScoreTqReqEnqueueCeiling_Entry
0545 ScoreTqReqEnqueueCeiling_Entries[] = {
0546 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA },
0547 #if defined(RTEMS_SMP)
0548 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_SecondQueue },
0549 #else
0550 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA },
0551 #endif
0552 #if defined(RTEMS_SMP)
0553 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_SecondFirst },
0554 #else
0555 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA },
0556 #endif
0557 #if defined(RTEMS_SMP)
0558 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_FirstFirst },
0559 #else
0560 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA },
0561 #endif
0562 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_InitialFirst },
0563 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_Second },
0564 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_First },
0565 #if defined(RTEMS_SMP)
0566 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_InitialFirst },
0567 #else
0568 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA },
0569 #endif
0570 #if defined(RTEMS_SMP)
0571 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_Second },
0572 #else
0573 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA },
0574 #endif
0575 #if defined(RTEMS_SMP)
0576 { 0, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_First }
0577 #else
0578 { 1, 0, 0, 0, ScoreTqReqEnqueueCeiling_Post_Position_NA }
0579 #endif
0580 };
0581
0582 static const uint8_t
0583 ScoreTqReqEnqueueCeiling_Map[] = {
0584 4, 0, 0, 5, 1, 2, 6, 1, 3, 7, 0, 0, 8, 1, 2, 9, 1, 3
0585 };
0586
0587 static size_t ScoreTqReqEnqueueCeiling_Scope( void *arg, char *buf, size_t n )
0588 {
0589 ScoreTqReqEnqueueCeiling_Context *ctx;
0590
0591 ctx = arg;
0592
0593 if ( ctx->Map.in_action_loop ) {
0594 return T_get_scope(
0595 ScoreTqReqEnqueueCeiling_PreDesc,
0596 buf,
0597 n,
0598 ctx->Map.pcs
0599 );
0600 }
0601
0602 return 0;
0603 }
0604
0605 static T_fixture ScoreTqReqEnqueueCeiling_Fixture = {
0606 .setup = ScoreTqReqEnqueueCeiling_Setup_Wrap,
0607 .stop = NULL,
0608 .teardown = ScoreTqReqEnqueueCeiling_Teardown_Wrap,
0609 .scope = ScoreTqReqEnqueueCeiling_Scope,
0610 .initial_context = &ScoreTqReqEnqueueCeiling_Instance
0611 };
0612
0613 static inline ScoreTqReqEnqueueCeiling_Entry ScoreTqReqEnqueueCeiling_PopEntry(
0614 ScoreTqReqEnqueueCeiling_Context *ctx
0615 )
0616 {
0617 size_t index;
0618
0619 index = ctx->Map.index;
0620 ctx->Map.index = index + 1;
0621 return ScoreTqReqEnqueueCeiling_Entries[
0622 ScoreTqReqEnqueueCeiling_Map[ index ]
0623 ];
0624 }
0625
0626 static void ScoreTqReqEnqueueCeiling_TestVariant(
0627 ScoreTqReqEnqueueCeiling_Context *ctx
0628 )
0629 {
0630 ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_Prepare(
0631 ctx,
0632 ctx->Map.pcs[ 0 ]
0633 );
0634 ScoreTqReqEnqueueCeiling_Pre_QueueEligible_Prepare( ctx, ctx->Map.pcs[ 1 ] );
0635 ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_Prepare(
0636 ctx,
0637 ctx->Map.pcs[ 2 ]
0638 );
0639 ScoreTqReqEnqueueCeiling_Action( ctx );
0640 ScoreTqReqEnqueueCeiling_Post_Position_Check(
0641 ctx,
0642 ctx->Map.entry.Post_Position
0643 );
0644 }
0645
0646 static T_fixture_node ScoreTqReqEnqueueCeiling_Node;
0647
0648 static T_remark ScoreTqReqEnqueueCeiling_Remark = {
0649 .next = NULL,
0650 .remark = "ScoreTqReqEnqueueCeiling"
0651 };
0652
0653 void ScoreTqReqEnqueueCeiling_Run( TQContext *tq_ctx )
0654 {
0655 ScoreTqReqEnqueueCeiling_Context *ctx;
0656
0657 ctx = &ScoreTqReqEnqueueCeiling_Instance;
0658 ctx->tq_ctx = tq_ctx;
0659
0660 ctx = T_push_fixture(
0661 &ScoreTqReqEnqueueCeiling_Node,
0662 &ScoreTqReqEnqueueCeiling_Fixture
0663 );
0664 ctx->Map.in_action_loop = true;
0665 ctx->Map.index = 0;
0666
0667 for (
0668 ctx->Map.pcs[ 0 ] = ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_Home;
0669 ctx->Map.pcs[ 0 ] < ScoreTqReqEnqueueCeiling_Pre_EligibleScheduler_NA;
0670 ++ctx->Map.pcs[ 0 ]
0671 ) {
0672 for (
0673 ctx->Map.pcs[ 1 ] = ScoreTqReqEnqueueCeiling_Pre_QueueEligible_None;
0674 ctx->Map.pcs[ 1 ] < ScoreTqReqEnqueueCeiling_Pre_QueueEligible_NA;
0675 ++ctx->Map.pcs[ 1 ]
0676 ) {
0677 for (
0678 ctx->Map.pcs[ 2 ] = ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_None;
0679 ctx->Map.pcs[ 2 ] < ScoreTqReqEnqueueCeiling_Pre_QueueIneligible_NA;
0680 ++ctx->Map.pcs[ 2 ]
0681 ) {
0682 ctx->Map.entry = ScoreTqReqEnqueueCeiling_PopEntry( ctx );
0683 ScoreTqReqEnqueueCeiling_Prepare( ctx );
0684 ScoreTqReqEnqueueCeiling_TestVariant( ctx );
0685 }
0686 }
0687 }
0688
0689 T_add_remark( &ScoreTqReqEnqueueCeiling_Remark );
0690 T_pop_fixture();
0691 }
0692
0693