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-deadlock.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_Notification_NA : 1;
0070 uint8_t Pre_Deadlock_NA : 1;
0071 uint8_t Post_Result : 2;
0072 } ScoreTqReqEnqueueDeadlock_Entry;
0073
0074
0075
0076
0077 typedef struct {
0078
0079
0080
0081
0082 bool more;
0083
0084
0085
0086
0087
0088 TQContext *tq_ctx;
0089
0090 struct {
0091
0092
0093
0094 size_t pcs[ 2 ];
0095
0096
0097
0098
0099 bool in_action_loop;
0100
0101
0102
0103
0104 size_t index;
0105
0106
0107
0108
0109 ScoreTqReqEnqueueDeadlock_Entry entry;
0110
0111
0112
0113
0114
0115 bool skip;
0116 } Map;
0117 } ScoreTqReqEnqueueDeadlock_Context;
0118
0119 static ScoreTqReqEnqueueDeadlock_Context
0120 ScoreTqReqEnqueueDeadlock_Instance;
0121
0122 static const char * const ScoreTqReqEnqueueDeadlock_PreDesc_Notification[] = {
0123 "Status",
0124 "Fatal",
0125 "NA"
0126 };
0127
0128 static const char * const ScoreTqReqEnqueueDeadlock_PreDesc_Deadlock[] = {
0129 "One",
0130 "More",
0131 "NA"
0132 };
0133
0134 static const char * const * const ScoreTqReqEnqueueDeadlock_PreDesc[] = {
0135 ScoreTqReqEnqueueDeadlock_PreDesc_Notification,
0136 ScoreTqReqEnqueueDeadlock_PreDesc_Deadlock,
0137 NULL
0138 };
0139
0140 static void ScoreTqReqEnqueueDeadlock_Pre_Notification_Prepare(
0141 ScoreTqReqEnqueueDeadlock_Context *ctx,
0142 ScoreTqReqEnqueueDeadlock_Pre_Notification state
0143 )
0144 {
0145 switch ( state ) {
0146 case ScoreTqReqEnqueueDeadlock_Pre_Notification_Status: {
0147
0148
0149
0150 if ( ctx->tq_ctx->deadlock != TQ_DEADLOCK_STATUS ) {
0151 ctx->Map.skip = true;
0152 }
0153 break;
0154 }
0155
0156 case ScoreTqReqEnqueueDeadlock_Pre_Notification_Fatal: {
0157
0158
0159
0160 if ( ctx->tq_ctx->deadlock != TQ_DEADLOCK_FATAL ) {
0161 ctx->Map.skip = true;
0162 }
0163 break;
0164 }
0165
0166 case ScoreTqReqEnqueueDeadlock_Pre_Notification_NA:
0167 break;
0168 }
0169 }
0170
0171 static void ScoreTqReqEnqueueDeadlock_Pre_Deadlock_Prepare(
0172 ScoreTqReqEnqueueDeadlock_Context *ctx,
0173 ScoreTqReqEnqueueDeadlock_Pre_Deadlock state
0174 )
0175 {
0176 switch ( state ) {
0177 case ScoreTqReqEnqueueDeadlock_Pre_Deadlock_One: {
0178
0179
0180
0181
0182 ctx->more = false;
0183 break;
0184 }
0185
0186 case ScoreTqReqEnqueueDeadlock_Pre_Deadlock_More: {
0187
0188
0189
0190
0191
0192
0193 ctx->more = true;
0194 break;
0195 }
0196
0197 case ScoreTqReqEnqueueDeadlock_Pre_Deadlock_NA:
0198 break;
0199 }
0200 }
0201
0202 static void ScoreTqReqEnqueueDeadlock_Post_Result_Check(
0203 ScoreTqReqEnqueueDeadlock_Context *ctx,
0204 ScoreTqReqEnqueueDeadlock_Post_Result state
0205 )
0206 {
0207 switch ( state ) {
0208 case ScoreTqReqEnqueueDeadlock_Post_Result_Status: {
0209
0210
0211
0212
0213
0214 break;
0215 }
0216
0217 case ScoreTqReqEnqueueDeadlock_Post_Result_Fatal: {
0218
0219
0220
0221
0222
0223 break;
0224 }
0225
0226 case ScoreTqReqEnqueueDeadlock_Post_Result_NA:
0227 break;
0228 }
0229 }
0230
0231 static void ScoreTqReqEnqueueDeadlock_Action(
0232 ScoreTqReqEnqueueDeadlock_Context *ctx
0233 )
0234 {
0235 Status_Control status;
0236
0237 if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) {
0238 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_A, SCHEDULER_B_ID, PRIO_NORMAL );
0239 } else {
0240 TQSetScheduler(
0241 ctx->tq_ctx,
0242 TQ_BLOCKER_A,
0243 SCHEDULER_A_ID,
0244 PRIO_VERY_HIGH
0245 );
0246 }
0247
0248 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_B, SCHEDULER_A_ID, PRIO_HIGH );
0249 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_C, SCHEDULER_A_ID, PRIO_HIGH );
0250
0251 TQSortMutexesByID( ctx->tq_ctx );
0252 TQMutexObtain( ctx->tq_ctx, TQ_MUTEX_C );
0253 TQSendAndWaitForExecutionStop( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_ENQUEUE );
0254
0255 if ( ctx->more ) {
0256 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_MUTEX_A_OBTAIN );
0257 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_MUTEX_C_OBTAIN );
0258 Yield();
0259 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_MUTEX_B_OBTAIN );
0260 Yield();
0261 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_MUTEX_A_OBTAIN );
0262 Yield();
0263 TQSendAndWaitForExecutionStop(
0264 ctx->tq_ctx,
0265 TQ_BLOCKER_A,
0266 TQ_EVENT_MUTEX_B_OBTAIN
0267 );
0268 } else {
0269 TQSendAndWaitForExecutionStop(
0270 ctx->tq_ctx,
0271 TQ_BLOCKER_A,
0272 TQ_EVENT_MUTEX_C_OBTAIN
0273 );
0274 }
0275
0276 if ( ctx->tq_ctx->deadlock == TQ_DEADLOCK_FATAL ) {
0277 status = TQEnqueueFatal( ctx->tq_ctx );
0278 T_eq_int( status, STATUS_DEADLOCK );
0279 } else {
0280 status = TQEnqueue( ctx->tq_ctx, TQ_WAIT_FOREVER );
0281 T_eq_int( status, TQConvertStatus( ctx->tq_ctx, STATUS_DEADLOCK ) );
0282 }
0283
0284 TQMutexRelease( ctx->tq_ctx, TQ_MUTEX_C );
0285
0286 if ( ctx->more ) {
0287 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_MUTEX_C_RELEASE );
0288 TQSend( ctx->tq_ctx, TQ_BLOCKER_B, TQ_EVENT_MUTEX_A_RELEASE );
0289 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_MUTEX_A_RELEASE );
0290 TQSend( ctx->tq_ctx, TQ_BLOCKER_C, TQ_EVENT_MUTEX_B_RELEASE );
0291 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_MUTEX_B_RELEASE );
0292 } else {
0293 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_MUTEX_C_RELEASE );
0294 }
0295
0296 if ( ctx->tq_ctx->enqueue_variant == TQ_ENQUEUE_STICKY ) {
0297 TQSend(
0298 ctx->tq_ctx,
0299 TQ_BLOCKER_A,
0300 TQ_EVENT_SURRENDER | TQ_EVENT_RUNNER_SYNC
0301 );
0302 TQSynchronizeRunner();
0303 TQSetScheduler( ctx->tq_ctx, TQ_BLOCKER_A, SCHEDULER_A_ID, PRIO_HIGH );
0304 } else {
0305 TQSend( ctx->tq_ctx, TQ_BLOCKER_A, TQ_EVENT_SURRENDER );
0306 }
0307 }
0308
0309 static const ScoreTqReqEnqueueDeadlock_Entry
0310 ScoreTqReqEnqueueDeadlock_Entries[] = {
0311 { 0, 0, 0, ScoreTqReqEnqueueDeadlock_Post_Result_Status },
0312 { 0, 0, 0, ScoreTqReqEnqueueDeadlock_Post_Result_Fatal }
0313 };
0314
0315 static const uint8_t
0316 ScoreTqReqEnqueueDeadlock_Map[] = {
0317 0, 0, 1, 1
0318 };
0319
0320 static size_t ScoreTqReqEnqueueDeadlock_Scope( void *arg, char *buf, size_t n )
0321 {
0322 ScoreTqReqEnqueueDeadlock_Context *ctx;
0323
0324 ctx = arg;
0325
0326 if ( ctx->Map.in_action_loop ) {
0327 return T_get_scope(
0328 ScoreTqReqEnqueueDeadlock_PreDesc,
0329 buf,
0330 n,
0331 ctx->Map.pcs
0332 );
0333 }
0334
0335 return 0;
0336 }
0337
0338 static T_fixture ScoreTqReqEnqueueDeadlock_Fixture = {
0339 .setup = NULL,
0340 .stop = NULL,
0341 .teardown = NULL,
0342 .scope = ScoreTqReqEnqueueDeadlock_Scope,
0343 .initial_context = &ScoreTqReqEnqueueDeadlock_Instance
0344 };
0345
0346 static const uint8_t ScoreTqReqEnqueueDeadlock_Weights[] = {
0347 2, 1
0348 };
0349
0350 static void ScoreTqReqEnqueueDeadlock_Skip(
0351 ScoreTqReqEnqueueDeadlock_Context *ctx,
0352 size_t index
0353 )
0354 {
0355 switch ( index + 1 ) {
0356 case 1:
0357 ctx->Map.pcs[ 1 ] = ScoreTqReqEnqueueDeadlock_Pre_Deadlock_NA - 1;
0358 break;
0359 }
0360 }
0361
0362 static inline ScoreTqReqEnqueueDeadlock_Entry
0363 ScoreTqReqEnqueueDeadlock_PopEntry( ScoreTqReqEnqueueDeadlock_Context *ctx )
0364 {
0365 size_t index;
0366
0367 if ( ctx->Map.skip ) {
0368 size_t i;
0369
0370 ctx->Map.skip = false;
0371 index = 0;
0372
0373 for ( i = 0; i < 2; ++i ) {
0374 index += ScoreTqReqEnqueueDeadlock_Weights[ i ] * ctx->Map.pcs[ i ];
0375 }
0376 } else {
0377 index = ctx->Map.index;
0378 }
0379
0380 ctx->Map.index = index + 1;
0381
0382 return ScoreTqReqEnqueueDeadlock_Entries[
0383 ScoreTqReqEnqueueDeadlock_Map[ index ]
0384 ];
0385 }
0386
0387 static void ScoreTqReqEnqueueDeadlock_TestVariant(
0388 ScoreTqReqEnqueueDeadlock_Context *ctx
0389 )
0390 {
0391 ScoreTqReqEnqueueDeadlock_Pre_Notification_Prepare( ctx, ctx->Map.pcs[ 0 ] );
0392
0393 if ( ctx->Map.skip ) {
0394 ScoreTqReqEnqueueDeadlock_Skip( ctx, 0 );
0395 return;
0396 }
0397
0398 ScoreTqReqEnqueueDeadlock_Pre_Deadlock_Prepare( ctx, ctx->Map.pcs[ 1 ] );
0399 ScoreTqReqEnqueueDeadlock_Action( ctx );
0400 ScoreTqReqEnqueueDeadlock_Post_Result_Check(
0401 ctx,
0402 ctx->Map.entry.Post_Result
0403 );
0404 }
0405
0406 static T_fixture_node ScoreTqReqEnqueueDeadlock_Node;
0407
0408 static T_remark ScoreTqReqEnqueueDeadlock_Remark = {
0409 .next = NULL,
0410 .remark = "ScoreTqReqEnqueueDeadlock"
0411 };
0412
0413 void ScoreTqReqEnqueueDeadlock_Run( TQContext *tq_ctx )
0414 {
0415 ScoreTqReqEnqueueDeadlock_Context *ctx;
0416
0417 ctx = &ScoreTqReqEnqueueDeadlock_Instance;
0418 ctx->tq_ctx = tq_ctx;
0419
0420 ctx = T_push_fixture(
0421 &ScoreTqReqEnqueueDeadlock_Node,
0422 &ScoreTqReqEnqueueDeadlock_Fixture
0423 );
0424 ctx->Map.in_action_loop = true;
0425 ctx->Map.index = 0;
0426 ctx->Map.skip = false;
0427
0428 for (
0429 ctx->Map.pcs[ 0 ] = ScoreTqReqEnqueueDeadlock_Pre_Notification_Status;
0430 ctx->Map.pcs[ 0 ] < ScoreTqReqEnqueueDeadlock_Pre_Notification_NA;
0431 ++ctx->Map.pcs[ 0 ]
0432 ) {
0433 for (
0434 ctx->Map.pcs[ 1 ] = ScoreTqReqEnqueueDeadlock_Pre_Deadlock_One;
0435 ctx->Map.pcs[ 1 ] < ScoreTqReqEnqueueDeadlock_Pre_Deadlock_NA;
0436 ++ctx->Map.pcs[ 1 ]
0437 ) {
0438 ctx->Map.entry = ScoreTqReqEnqueueDeadlock_PopEntry( ctx );
0439 ScoreTqReqEnqueueDeadlock_TestVariant( ctx );
0440 }
0441 }
0442
0443 T_add_remark( &ScoreTqReqEnqueueDeadlock_Remark );
0444 T_pop_fixture();
0445 }
0446
0447