File indexing completed on 2025-05-11 08:24:44
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 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031
0032 #include <rtems.h>
0033 #include <rtems/thread.h>
0034 #include <rtems/score/threadimpl.h>
0035
0036 #include <tmacros.h>
0037
0038 const char rtems_test_name[] = "SMPTHREADPIN 1";
0039
0040 #define CPU_COUNT 2
0041
0042 #define SCHED_A rtems_build_name(' ', ' ', ' ', 'A')
0043
0044 #define SCHED_B rtems_build_name(' ', ' ', ' ', 'B')
0045
0046 #define EVENT_WAKEUP_MASTER RTEMS_EVENT_0
0047
0048 #define EVENT_MTX_LOCK RTEMS_EVENT_1
0049
0050 #define EVENT_MTX_UNLOCK RTEMS_EVENT_2
0051
0052 #define EVENT_MOVE_BUSY_TO_CPU_0 RTEMS_EVENT_3
0053
0054 #define EVENT_MOVE_BUSY_TO_CPU_1 RTEMS_EVENT_4
0055
0056 #define EVENT_MOVE_SELF_TO_CPU_0 RTEMS_EVENT_5
0057
0058 #define EVENT_MOVE_SELF_TO_CPU_1 RTEMS_EVENT_6
0059
0060 #define EVENT_SET_SELF_PRIO_TO_LOW RTEMS_EVENT_7
0061
0062 #define EVENT_SET_BUSY_PRIO_TO_IDLE RTEMS_EVENT_8
0063
0064 #define EVENT_SET_FLAG RTEMS_EVENT_9
0065
0066 #define PRIO_IDLE 6
0067
0068 #define PRIO_VERY_LOW 5
0069
0070 #define PRIO_LOW 4
0071
0072 #define PRIO_MIDDLE 3
0073
0074 #define PRIO_HIGH 2
0075
0076 #define PRIO_VERY_HIGH 1
0077
0078 typedef struct {
0079 rtems_id master;
0080 rtems_id event;
0081 rtems_id event_2;
0082 rtems_id busy;
0083 rtems_id sched_a;
0084 rtems_id sched_b;
0085 rtems_mutex mtx;
0086 volatile bool flag;
0087 } test_context;
0088
0089 static test_context test_instance;
0090
0091 static rtems_task_priority set_prio(rtems_id id, rtems_task_priority prio)
0092 {
0093 rtems_status_code sc;
0094 rtems_task_priority old_prio;
0095
0096 old_prio = 0xffffffff;
0097 sc = rtems_task_set_priority(id, prio, &old_prio);
0098 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0099
0100 return old_prio;
0101 }
0102
0103 static void set_affinity(rtems_id task, uint32_t cpu_index)
0104 {
0105 rtems_status_code sc;
0106 rtems_id sched_cpu;
0107 rtems_id sched_task;
0108 cpu_set_t set;
0109
0110 sc = rtems_scheduler_ident_by_processor(cpu_index, &sched_cpu);
0111 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0112
0113 sc = rtems_task_get_scheduler(task, &sched_task);
0114 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0115
0116 if (sched_task != sched_cpu) {
0117 rtems_task_priority prio;
0118
0119 CPU_FILL(&set);
0120 sc = rtems_task_set_affinity(task, sizeof(set), &set);
0121 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0122
0123 prio = set_prio(task, RTEMS_CURRENT_PRIORITY);
0124 sc = rtems_task_set_scheduler(task, sched_cpu, prio);
0125 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0126 }
0127
0128 CPU_ZERO(&set);
0129 CPU_SET((int) cpu_index, &set);
0130 sc = rtems_task_set_affinity(task, sizeof(set), &set);
0131 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0132 }
0133
0134 static void send_events(rtems_id task, rtems_event_set events)
0135 {
0136 rtems_status_code sc;
0137
0138 sc = rtems_event_send(task, events);
0139 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0140 }
0141
0142 static rtems_event_set wait_for_events(void)
0143 {
0144 rtems_event_set events;
0145 rtems_status_code sc;
0146
0147 sc = rtems_event_receive(
0148 RTEMS_ALL_EVENTS,
0149 RTEMS_EVENT_ANY | RTEMS_WAIT,
0150 RTEMS_NO_TIMEOUT,
0151 &events
0152 );
0153 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0154
0155 return events;
0156 }
0157
0158 static void pin(bool blocked)
0159 {
0160 Per_CPU_Control *cpu_self;
0161 Thread_Control *executing;
0162
0163 cpu_self = _Thread_Dispatch_disable();
0164 executing = _Per_CPU_Get_executing(cpu_self);
0165
0166 if (blocked) {
0167 _Thread_Set_state(executing, STATES_SUSPENDED);
0168 }
0169
0170 _Thread_Pin(executing);
0171
0172 if (blocked) {
0173 _Thread_Clear_state(executing, STATES_SUSPENDED);
0174 }
0175
0176 _Thread_Dispatch_enable(cpu_self);
0177 }
0178
0179 static void unpin(bool blocked)
0180 {
0181 Per_CPU_Control *cpu_self;
0182 Thread_Control *executing;
0183
0184 cpu_self = _Thread_Dispatch_disable();
0185 executing = _Per_CPU_Get_executing(cpu_self);
0186
0187 if (blocked) {
0188 _Thread_Set_state(executing, STATES_SUSPENDED);
0189 }
0190
0191 _Thread_Unpin(executing, cpu_self);
0192
0193 if (blocked) {
0194 _Thread_Clear_state(executing, STATES_SUSPENDED);
0195 }
0196
0197 _Thread_Dispatch_enable(cpu_self);
0198 }
0199
0200 static void event_task(rtems_task_argument arg)
0201 {
0202 test_context *ctx;
0203
0204 ctx = (test_context *) arg;
0205
0206 while (true) {
0207 rtems_event_set events;
0208
0209 events = wait_for_events();
0210
0211
0212
0213
0214
0215 if ((events & EVENT_MTX_LOCK) != 0) {
0216 rtems_mutex_lock(&ctx->mtx);
0217 }
0218
0219 if ((events & EVENT_MTX_UNLOCK) != 0) {
0220 rtems_mutex_unlock(&ctx->mtx);
0221 }
0222
0223 if ((events & EVENT_MOVE_BUSY_TO_CPU_0) != 0) {
0224 set_affinity(ctx->busy, 0);
0225 }
0226
0227 if ((events & EVENT_MOVE_BUSY_TO_CPU_1) != 0) {
0228 set_affinity(ctx->busy, 1);
0229 }
0230
0231 if ((events & EVENT_MOVE_SELF_TO_CPU_0) != 0) {
0232 set_affinity(RTEMS_SELF, 0);
0233 }
0234
0235 if ((events & EVENT_MOVE_SELF_TO_CPU_1) != 0) {
0236 set_affinity(RTEMS_SELF, 1);
0237 }
0238
0239 if ((events & EVENT_SET_SELF_PRIO_TO_LOW) != 0) {
0240 set_prio(RTEMS_SELF, PRIO_LOW);
0241 }
0242
0243 if ((events & EVENT_SET_BUSY_PRIO_TO_IDLE) != 0) {
0244 set_prio(ctx->busy, PRIO_IDLE);
0245 }
0246
0247 if ((events & EVENT_SET_FLAG) != 0) {
0248 ctx->flag = true;
0249 }
0250
0251 if ((events & EVENT_WAKEUP_MASTER) != 0) {
0252 send_events(ctx->master, EVENT_WAKEUP_MASTER);
0253 }
0254 }
0255 }
0256
0257 static void busy_task(rtems_task_argument arg)
0258 {
0259 (void) arg;
0260
0261 _CPU_Thread_Idle_body(0);
0262 }
0263
0264 static const char *blocked_or_ready(bool blocked)
0265 {
0266 return blocked ? "blocked" : "ready";
0267 }
0268
0269 static void reconfigure_scheduler(test_context *ctx)
0270 {
0271 rtems_status_code sc;
0272
0273 puts("reconfigure scheduler");
0274
0275 set_prio(ctx->master, PRIO_MIDDLE);
0276 set_prio(ctx->event, PRIO_LOW);
0277 set_prio(ctx->event_2, PRIO_VERY_LOW);
0278 set_prio(ctx->busy, PRIO_IDLE);
0279
0280 set_affinity(ctx->master, 0);
0281 set_affinity(ctx->event, 0);
0282 set_affinity(ctx->event_2, 0);
0283 set_affinity(ctx->busy, 0);
0284
0285 sc = rtems_scheduler_remove_processor(ctx->sched_a, 1);
0286 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0287
0288 sc = rtems_scheduler_add_processor(ctx->sched_b, 1);
0289 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0290 }
0291
0292 static void test_simple_pin_unpin(test_context *ctx, int run)
0293 {
0294 Per_CPU_Control *cpu_self;
0295 Thread_Control *executing;
0296
0297 printf("test simple wait unpin (run %i)\n", run);
0298
0299 set_affinity(ctx->busy, 0);
0300 set_prio(ctx->busy, PRIO_IDLE);
0301 set_prio(RTEMS_SELF, PRIO_MIDDLE);
0302 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0303
0304 cpu_self = _Thread_Dispatch_disable();
0305 executing = _Per_CPU_Get_executing(cpu_self);
0306 _Thread_Pin(executing);
0307
0308 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0309
0310 _Thread_Unpin(executing, cpu_self);
0311 _Thread_Dispatch_enable(cpu_self);
0312
0313 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0314 }
0315
0316 static void test_pin_wait_unpin(test_context *ctx, bool blocked, int run)
0317 {
0318 printf("test pin wait unpin (%s, run %i)\n", blocked_or_ready(blocked), run);
0319
0320 set_affinity(ctx->busy, 0);
0321 set_prio(ctx->busy, PRIO_IDLE);
0322 set_prio(RTEMS_SELF, PRIO_MIDDLE);
0323 set_prio(ctx->event, PRIO_LOW);
0324 set_affinity(ctx->event, 1);
0325 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0326
0327 pin(blocked);
0328 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0329
0330 send_events(ctx->event, EVENT_WAKEUP_MASTER);
0331 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0332 wait_for_events();
0333 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0334
0335 set_prio(ctx->busy, PRIO_HIGH);
0336 set_affinity(ctx->busy, 0);
0337 unpin(blocked);
0338 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0339 }
0340
0341 static void test_pin_preempt_unpin(test_context *ctx, bool blocked, int run)
0342 {
0343 printf(
0344 "test pin preempt unpin (%s, run %i)\n",
0345 blocked_or_ready(blocked),
0346 run
0347 );
0348
0349 set_prio(RTEMS_SELF, PRIO_MIDDLE);
0350 set_prio(ctx->event, PRIO_VERY_HIGH);
0351 set_prio(ctx->busy, PRIO_HIGH);
0352 set_affinity(ctx->event, 0);
0353 set_affinity(ctx->busy, 0);
0354 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0355
0356 pin(blocked);
0357 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0358
0359 ctx->flag = false;
0360 send_events(
0361 ctx->event,
0362 EVENT_MOVE_BUSY_TO_CPU_1 | EVENT_SET_SELF_PRIO_TO_LOW
0363 | EVENT_SET_BUSY_PRIO_TO_IDLE | EVENT_SET_FLAG
0364 );
0365
0366 while (!ctx->flag) {
0367 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0368 }
0369
0370 set_affinity(ctx->busy, 0);
0371 unpin(blocked);
0372 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0373 }
0374
0375 static void test_pin_home_no_help_unpin(
0376 test_context *ctx,
0377 bool blocked,
0378 int run
0379 )
0380 {
0381 rtems_status_code sc;
0382
0383 printf(
0384 "test pin home no help unpin (%s, run %i)\n",
0385 blocked_or_ready(blocked),
0386 run
0387 );
0388
0389 set_affinity(ctx->busy, 1);
0390 set_prio(ctx->busy, PRIO_IDLE);
0391 set_prio(RTEMS_SELF, PRIO_MIDDLE);
0392 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0393
0394 pin(blocked);
0395 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0396
0397 sc = rtems_task_set_scheduler(RTEMS_SELF, ctx->sched_b, 1);
0398 rtems_test_assert(sc == RTEMS_RESOURCE_IN_USE);
0399
0400 rtems_mutex_lock(&ctx->mtx);
0401 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0402
0403 set_affinity(ctx->event, 1);
0404 set_prio(ctx->event, PRIO_MIDDLE);
0405
0406 send_events(ctx->event, EVENT_MTX_LOCK);
0407 set_prio(ctx->event_2, PRIO_LOW);
0408 set_affinity(ctx->event_2, 1);
0409 send_events(ctx->event_2, EVENT_WAKEUP_MASTER);
0410 wait_for_events();
0411
0412
0413 rtems_test_assert(ctx->mtx._Queue._heads != NULL);
0414 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0415
0416 set_affinity(ctx->event_2, 0);
0417 set_affinity(ctx->busy, 1);
0418 set_prio(ctx->busy, PRIO_HIGH);
0419 send_events(
0420 ctx->event_2,
0421 EVENT_MOVE_BUSY_TO_CPU_0 | EVENT_MOVE_SELF_TO_CPU_1
0422 | EVENT_SET_SELF_PRIO_TO_LOW | EVENT_SET_BUSY_PRIO_TO_IDLE
0423 );
0424 set_prio(ctx->event_2, PRIO_VERY_HIGH);
0425 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0426
0427 rtems_mutex_unlock(&ctx->mtx);
0428 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0429
0430 send_events(ctx->event, EVENT_WAKEUP_MASTER | EVENT_MTX_UNLOCK);
0431 wait_for_events();
0432 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0433
0434 unpin(blocked);
0435 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0436 }
0437
0438 static void test_pin_foreign_no_help_unpin(
0439 test_context *ctx,
0440 bool blocked,
0441 int run
0442 )
0443 {
0444 printf(
0445 "test pin foreign no help unpin (%s, run %i)\n",
0446 blocked_or_ready(blocked),
0447 run
0448 );
0449
0450 set_affinity(ctx->busy, 1);
0451 set_prio(ctx->busy, PRIO_IDLE);
0452 set_prio(RTEMS_SELF, PRIO_MIDDLE);
0453 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0454
0455 rtems_mutex_lock(&ctx->mtx);
0456 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0457
0458 set_affinity(ctx->event, 1);
0459 set_prio(ctx->event, PRIO_MIDDLE);
0460 send_events(ctx->event, EVENT_MTX_LOCK);
0461 set_prio(ctx->event_2, PRIO_LOW);
0462 set_affinity(ctx->event_2, 1);
0463 send_events(ctx->event_2, EVENT_WAKEUP_MASTER);
0464 wait_for_events();
0465
0466
0467 rtems_test_assert(ctx->mtx._Queue._heads != NULL);
0468 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0469
0470
0471 set_affinity(ctx->busy, 0);
0472 set_prio(ctx->busy, PRIO_HIGH);
0473 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0474
0475
0476 pin(blocked);
0477 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0478
0479 set_affinity(ctx->event_2, 1);
0480 send_events(
0481 ctx->event_2,
0482 EVENT_MOVE_BUSY_TO_CPU_1 | EVENT_MOVE_SELF_TO_CPU_0
0483 | EVENT_SET_SELF_PRIO_TO_LOW | EVENT_SET_BUSY_PRIO_TO_IDLE
0484 );
0485 set_prio(ctx->event_2, PRIO_VERY_HIGH);
0486 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0487
0488 unpin(blocked);
0489 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0490
0491 set_prio(ctx->busy, PRIO_IDLE);
0492 rtems_mutex_unlock(&ctx->mtx);
0493 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0494
0495 send_events(ctx->event, EVENT_WAKEUP_MASTER | EVENT_MTX_UNLOCK);
0496 wait_for_events();
0497 rtems_test_assert(rtems_scheduler_get_processor() == 0);
0498 }
0499
0500 static void test(test_context *ctx)
0501 {
0502 rtems_status_code sc;
0503 int run;
0504
0505 ctx->master = rtems_task_self();
0506
0507 rtems_mutex_init(&ctx->mtx, "test");
0508
0509 sc = rtems_scheduler_ident(SCHED_A, &ctx->sched_a);
0510 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0511
0512 sc = rtems_scheduler_ident(SCHED_B, &ctx->sched_b);
0513 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0514
0515 sc = rtems_task_create(
0516 rtems_build_name('B', 'U', 'S', 'Y'),
0517 PRIO_HIGH,
0518 RTEMS_MINIMUM_STACK_SIZE,
0519 RTEMS_DEFAULT_MODES,
0520 RTEMS_DEFAULT_ATTRIBUTES,
0521 &ctx->busy
0522 );
0523 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0524
0525 sc = rtems_task_start(ctx->busy, busy_task, (rtems_task_argument) ctx);
0526 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0527
0528 set_affinity(ctx->busy, 0);
0529 set_prio(ctx->busy, PRIO_IDLE);
0530 rtems_test_assert(rtems_scheduler_get_processor() == 1);
0531
0532 sc = rtems_task_create(
0533 rtems_build_name('E', 'V', 'T', '1'),
0534 PRIO_LOW,
0535 RTEMS_MINIMUM_STACK_SIZE,
0536 RTEMS_DEFAULT_MODES,
0537 RTEMS_DEFAULT_ATTRIBUTES,
0538 &ctx->event
0539 );
0540 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0541
0542 sc = rtems_task_start(ctx->event, event_task, (rtems_task_argument) ctx);
0543 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0544
0545 send_events(ctx->event, EVENT_WAKEUP_MASTER);
0546 wait_for_events();
0547
0548 sc = rtems_task_create(
0549 rtems_build_name('E', 'V', 'T', '2'),
0550 PRIO_LOW,
0551 RTEMS_MINIMUM_STACK_SIZE,
0552 RTEMS_DEFAULT_MODES,
0553 RTEMS_DEFAULT_ATTRIBUTES,
0554 &ctx->event_2
0555 );
0556 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0557
0558 sc = rtems_task_start(ctx->event_2, event_task, (rtems_task_argument) ctx);
0559 rtems_test_assert(sc == RTEMS_SUCCESSFUL);
0560
0561 send_events(ctx->event_2, EVENT_WAKEUP_MASTER);
0562 wait_for_events();
0563
0564 for (run = 1; run <= 3; ++run) {
0565 test_simple_pin_unpin(ctx, run);
0566 test_pin_wait_unpin(ctx, true, run);
0567 test_pin_wait_unpin(ctx, false, run);
0568 test_pin_preempt_unpin(ctx, true, run);
0569 test_pin_preempt_unpin(ctx, false, run);
0570 }
0571
0572 reconfigure_scheduler(ctx);
0573
0574 for (run = 1; run <= 3; ++run) {
0575 test_pin_home_no_help_unpin(ctx, true, run);
0576 test_pin_home_no_help_unpin(ctx, false, run);
0577 test_pin_foreign_no_help_unpin(ctx, true, run);
0578 test_pin_foreign_no_help_unpin(ctx, false, run);
0579 }
0580 }
0581
0582 static void Init(rtems_task_argument arg)
0583 {
0584 TEST_BEGIN();
0585
0586 if (rtems_scheduler_get_processor_maximum() == CPU_COUNT) {
0587 test(&test_instance);
0588 } else {
0589 puts("warning: wrong processor count to run the test");
0590 }
0591
0592 TEST_END();
0593 rtems_test_exit(0);
0594 }
0595
0596 #define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
0597 #define CONFIGURE_APPLICATION_NEEDS_SIMPLE_CONSOLE_DRIVER
0598
0599 #define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
0600
0601 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0602
0603 #define CONFIGURE_MAXIMUM_TASKS 4
0604
0605 #define CONFIGURE_INIT_TASK_PRIORITY PRIO_MIDDLE
0606
0607 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0608
0609 #define CONFIGURE_SCHEDULER_EDF_SMP
0610
0611 #include <rtems/scheduler.h>
0612
0613 RTEMS_SCHEDULER_EDF_SMP(a);
0614
0615 RTEMS_SCHEDULER_EDF_SMP(b);
0616
0617 #define CONFIGURE_SCHEDULER_TABLE_ENTRIES \
0618 RTEMS_SCHEDULER_TABLE_EDF_SMP(a, SCHED_A), \
0619 RTEMS_SCHEDULER_TABLE_EDF_SMP(b, SCHED_B) \
0620
0621 #define CONFIGURE_SCHEDULER_ASSIGNMENTS \
0622 RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_MANDATORY), \
0623 RTEMS_SCHEDULER_ASSIGN(0, RTEMS_SCHEDULER_ASSIGN_PROCESSOR_OPTIONAL)
0624
0625 #define CONFIGURE_INIT
0626
0627 #include <rtems/confdefs.h>