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 <rtems/score/threadimpl.h>
0056
0057 #include "tr-tq-timeout.h"
0058 #include "tx-support.h"
0059
0060 #include <rtems/test.h>
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070 typedef struct {
0071 uint8_t Skip : 1;
0072 uint8_t Pre_WaitState_NA : 1;
0073 uint8_t Post_Status : 2;
0074 uint8_t Post_Unblock : 2;
0075 } ScoreTqReqTimeout_Entry;
0076
0077
0078
0079
0080 typedef struct {
0081
0082
0083
0084 CallWithinISRRequest request;
0085
0086
0087
0088
0089
0090 TQContext *tq_ctx;
0091
0092 struct {
0093
0094
0095
0096 size_t pcs[ 1 ];
0097
0098
0099
0100
0101 bool in_action_loop;
0102
0103
0104
0105
0106 size_t index;
0107
0108
0109
0110
0111 ScoreTqReqTimeout_Entry entry;
0112
0113
0114
0115
0116
0117 bool skip;
0118 } Map;
0119 } ScoreTqReqTimeout_Context;
0120
0121 static ScoreTqReqTimeout_Context
0122 ScoreTqReqTimeout_Instance;
0123
0124 static const char * const ScoreTqReqTimeout_PreDesc_WaitState[] = {
0125 "Blocked",
0126 "IntendToBlock",
0127 "ReadyAgain",
0128 "NA"
0129 };
0130
0131 static const char * const * const ScoreTqReqTimeout_PreDesc[] = {
0132 ScoreTqReqTimeout_PreDesc_WaitState,
0133 NULL
0134 };
0135
0136 typedef ScoreTqReqTimeout_Context Context;
0137
0138 static const rtems_tcb *GetUnblock( Context *ctx, size_t *index )
0139 {
0140 return TQGetNextUnblock( ctx->tq_ctx, index )->thread;
0141 }
0142
0143 static const rtems_tcb *GetTCB( Context *ctx, TQWorkerKind worker )
0144 {
0145 return ctx->tq_ctx->worker_tcb[ worker ];
0146 }
0147
0148 static void Tick( void *arg )
0149 {
0150 Context *ctx;
0151
0152 ctx = arg;
0153 TQSchedulerRecordStart( ctx->tq_ctx );
0154 FinalClockTick();
0155 TQSchedulerRecordStop( ctx->tq_ctx );
0156 }
0157
0158 static void SchedulerBlock(
0159 void *arg,
0160 const T_scheduler_event *event,
0161 T_scheduler_when when
0162 )
0163 {
0164 Context *ctx;
0165
0166 ctx = arg;
0167
0168 if (
0169 when == T_SCHEDULER_BEFORE &&
0170 event->operation == T_SCHEDULER_BLOCK
0171 ) {
0172 T_scheduler_set_event_handler( NULL, NULL );
0173 ctx->request.handler = Tick;
0174 CallWithinISRSubmit( &ctx->request );
0175 }
0176 }
0177
0178 static void ThreadTimeout( void *arg )
0179 {
0180 Context *ctx;
0181
0182 ctx = arg;
0183 TQSchedulerRecordStart( ctx->tq_ctx );
0184 _Thread_Timeout(
0185 &ctx->tq_ctx->worker_tcb[ TQ_BLOCKER_A ]->Timer.Watchdog
0186 );
0187 TQSchedulerRecordStop( ctx->tq_ctx );
0188 }
0189
0190 static void SchedulerUnblock(
0191 void *arg,
0192 const T_scheduler_event *event,
0193 T_scheduler_when when
0194 )
0195 {
0196 Context *ctx;
0197
0198 ctx = arg;
0199
0200 if (
0201 when == T_SCHEDULER_BEFORE &&
0202 event->operation == T_SCHEDULER_UNBLOCK
0203 ) {
0204 T_scheduler_set_event_handler( NULL, NULL );
0205 ctx->request.handler = ThreadTimeout;
0206 CallWithinISRSubmit( &ctx->request );
0207 }
0208 }
0209
0210 static void ScoreTqReqTimeout_Pre_WaitState_Prepare(
0211 ScoreTqReqTimeout_Context *ctx,
0212 ScoreTqReqTimeout_Pre_WaitState state
0213 )
0214 {
0215 switch ( state ) {
0216 case ScoreTqReqTimeout_Pre_WaitState_Blocked: {
0217
0218
0219
0220
0221 TQEnqueuePrepare( ctx->tq_ctx );
0222 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0223 Yield();
0224 Tick( ctx );
0225 TQEnqueueDone( ctx->tq_ctx );
0226 break;
0227 }
0228
0229 case ScoreTqReqTimeout_Pre_WaitState_IntendToBlock: {
0230
0231
0232
0233
0234 TQEnqueuePrepare( ctx->tq_ctx );
0235 T_scheduler_set_event_handler( SchedulerBlock, ctx );
0236 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0237 Yield();
0238 TQEnqueueDone( ctx->tq_ctx );
0239 break;
0240 }
0241
0242 case ScoreTqReqTimeout_Pre_WaitState_ReadyAgain: {
0243
0244
0245
0246
0247 TQEnqueuePrepare( ctx->tq_ctx );
0248 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0249 Yield();
0250 T_scheduler_set_event_handler( SchedulerUnblock, ctx );
0251 TQEnqueueDone( ctx->tq_ctx );
0252 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_SURRENDER );
0253 break;
0254 }
0255
0256 case ScoreTqReqTimeout_Pre_WaitState_NA:
0257 break;
0258 }
0259 }
0260
0261 static void ScoreTqReqTimeout_Post_Status_Check(
0262 ScoreTqReqTimeout_Context *ctx,
0263 ScoreTqReqTimeout_Post_Status state
0264 )
0265 {
0266 switch ( state ) {
0267 case ScoreTqReqTimeout_Post_Status_Ok: {
0268
0269
0270
0271
0272 T_eq_int(
0273 ctx->tq_ctx->status[ TQ_BLOCKER_A ],
0274 TQConvertStatus( ctx->tq_ctx, STATUS_SUCCESSFUL )
0275 );
0276 break;
0277 }
0278
0279 case ScoreTqReqTimeout_Post_Status_Timeout: {
0280
0281
0282
0283
0284 T_eq_int(
0285 ctx->tq_ctx->status[ TQ_BLOCKER_A ],
0286 TQConvertStatus( ctx->tq_ctx, STATUS_TIMEOUT )
0287 );
0288 break;
0289 }
0290
0291 case ScoreTqReqTimeout_Post_Status_NA:
0292 break;
0293 }
0294 }
0295
0296 static void ScoreTqReqTimeout_Post_Unblock_Check(
0297 ScoreTqReqTimeout_Context *ctx,
0298 ScoreTqReqTimeout_Post_Unblock state
0299 )
0300 {
0301 size_t i;
0302
0303 i = 0;
0304
0305 switch ( state ) {
0306 case ScoreTqReqTimeout_Post_Unblock_Yes: {
0307
0308
0309
0310
0311 T_eq_ptr( GetUnblock( ctx, &i ), GetTCB( ctx, TQ_BLOCKER_A ) );
0312 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0313 break;
0314 }
0315
0316 case ScoreTqReqTimeout_Post_Unblock_No: {
0317
0318
0319
0320
0321 T_eq_ptr( GetUnblock( ctx, &i ), NULL );
0322 break;
0323 }
0324
0325 case ScoreTqReqTimeout_Post_Unblock_NA:
0326 break;
0327 }
0328 }
0329
0330 static void ScoreTqReqTimeout_Setup( ScoreTqReqTimeout_Context *ctx )
0331 {
0332 ctx->request.arg = ctx;
0333 TQReset( ctx->tq_ctx );
0334
0335 if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) {
0336 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_A, SCHEDULER_B_ID, PRIO_NORMAL );
0337 } else {
0338 TQSetPriority( ctx->tq_ctx, TQ_BLOCKER_A, PRIO_HIGH );
0339 }
0340 }
0341
0342 static void ScoreTqReqTimeout_Setup_Wrap( void *arg )
0343 {
0344 ScoreTqReqTimeout_Context *ctx;
0345
0346 ctx = arg;
0347 ctx->Map.in_action_loop = false;
0348 ScoreTqReqTimeout_Setup( ctx );
0349 }
0350
0351 static void ScoreTqReqTimeout_Teardown( ScoreTqReqTimeout_Context *ctx )
0352 {
0353 TQReset( ctx->tq_ctx );
0354 }
0355
0356 static void ScoreTqReqTimeout_Teardown_Wrap( void *arg )
0357 {
0358 ScoreTqReqTimeout_Context *ctx;
0359
0360 ctx = arg;
0361 ctx->Map.in_action_loop = false;
0362 ScoreTqReqTimeout_Teardown( ctx );
0363 }
0364
0365 static void ScoreTqReqTimeout_Action( ScoreTqReqTimeout_Context *ctx )
0366 {
0367
0368
0369
0370 }
0371
0372 static const ScoreTqReqTimeout_Entry
0373 ScoreTqReqTimeout_Entries[] = {
0374 { 0, 0, ScoreTqReqTimeout_Post_Status_Timeout,
0375 ScoreTqReqTimeout_Post_Unblock_Yes },
0376 { 0, 0, ScoreTqReqTimeout_Post_Status_Timeout,
0377 ScoreTqReqTimeout_Post_Unblock_No },
0378 { 0, 0, ScoreTqReqTimeout_Post_Status_Ok, ScoreTqReqTimeout_Post_Unblock_No }
0379 };
0380
0381 static const uint8_t
0382 ScoreTqReqTimeout_Map[] = {
0383 0, 1, 2
0384 };
0385
0386 static size_t ScoreTqReqTimeout_Scope( void *arg, char *buf, size_t n )
0387 {
0388 ScoreTqReqTimeout_Context *ctx;
0389
0390 ctx = arg;
0391
0392 if ( ctx->Map.in_action_loop ) {
0393 return T_get_scope( ScoreTqReqTimeout_PreDesc, buf, n, ctx->Map.pcs );
0394 }
0395
0396 return 0;
0397 }
0398
0399 static T_fixture ScoreTqReqTimeout_Fixture = {
0400 .setup = ScoreTqReqTimeout_Setup_Wrap,
0401 .stop = NULL,
0402 .teardown = ScoreTqReqTimeout_Teardown_Wrap,
0403 .scope = ScoreTqReqTimeout_Scope,
0404 .initial_context = &ScoreTqReqTimeout_Instance
0405 };
0406
0407 static inline ScoreTqReqTimeout_Entry ScoreTqReqTimeout_PopEntry(
0408 ScoreTqReqTimeout_Context *ctx
0409 )
0410 {
0411 size_t index;
0412
0413 index = ctx->Map.index;
0414 ctx->Map.index = index + 1;
0415 return ScoreTqReqTimeout_Entries[
0416 ScoreTqReqTimeout_Map[ index ]
0417 ];
0418 }
0419
0420 static void ScoreTqReqTimeout_TestVariant( ScoreTqReqTimeout_Context *ctx )
0421 {
0422 ScoreTqReqTimeout_Pre_WaitState_Prepare( ctx, ctx->Map.pcs[ 0 ] );
0423 ScoreTqReqTimeout_Action( ctx );
0424 ScoreTqReqTimeout_Post_Status_Check( ctx, ctx->Map.entry.Post_Status );
0425 ScoreTqReqTimeout_Post_Unblock_Check( ctx, ctx->Map.entry.Post_Unblock );
0426 }
0427
0428 static T_fixture_node ScoreTqReqTimeout_Node;
0429
0430 static T_remark ScoreTqReqTimeout_Remark = {
0431 .next = NULL,
0432 .remark = "ScoreTqReqTimeout"
0433 };
0434
0435 void ScoreTqReqTimeout_Run( TQContext *tq_ctx )
0436 {
0437 ScoreTqReqTimeout_Context *ctx;
0438
0439 ctx = &ScoreTqReqTimeout_Instance;
0440 ctx->tq_ctx = tq_ctx;
0441
0442 ctx = T_push_fixture( &ScoreTqReqTimeout_Node, &ScoreTqReqTimeout_Fixture );
0443 ctx->Map.in_action_loop = true;
0444 ctx->Map.index = 0;
0445
0446 for (
0447 ctx->Map.pcs[ 0 ] = ScoreTqReqTimeout_Pre_WaitState_Blocked;
0448 ctx->Map.pcs[ 0 ] < ScoreTqReqTimeout_Pre_WaitState_NA;
0449 ++ctx->Map.pcs[ 0 ]
0450 ) {
0451 ctx->Map.entry = ScoreTqReqTimeout_PopEntry( ctx );
0452 ScoreTqReqTimeout_TestVariant( ctx );
0453 }
0454
0455 T_add_remark( &ScoreTqReqTimeout_Remark );
0456 T_pop_fixture();
0457 }
0458
0459