File indexing completed on 2025-05-11 08:24:43
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 #include <rtems/score/smpimpl.h>
0029 #include <rtems/score/atomic.h>
0030 #include <rtems/score/threaddispatch.h>
0031 #include <rtems/sysinit.h>
0032 #include <rtems.h>
0033
0034 #include <string.h>
0035
0036 #include <rtems/test.h>
0037 #include <rtems/testopts.h>
0038 #include <tmacros.h>
0039
0040 #define CPU_COUNT 32
0041
0042 const char rtems_test_name[] = "SMPMULTICAST 1";
0043
0044 static const T_config config = {
0045 .name = "SMPMultiCast",
0046 .putchar = T_putchar_default,
0047 .verbosity = RTEMS_TEST_VERBOSITY,
0048 .now = T_now_clock
0049 };
0050
0051 typedef struct {
0052 rtems_test_parallel_context base;
0053 Atomic_Uint id[CPU_COUNT][CPU_COUNT];
0054 } test_context;
0055
0056 static test_context test_instance;
0057
0058 static void clear_ids_by_worker(test_context *ctx, size_t worker_index)
0059 {
0060 memset(&ctx->id[worker_index][0], 0, sizeof(ctx->id[worker_index]));
0061 }
0062
0063 static void unicast_action_irq_disabled(
0064 uint32_t cpu_index,
0065 SMP_Action_handler handler,
0066 void *arg
0067 )
0068 {
0069 rtems_interrupt_level level;
0070
0071 rtems_interrupt_local_disable(level);
0072 _SMP_Unicast_action(cpu_index, handler, arg);
0073 rtems_interrupt_local_enable(level);
0074 }
0075
0076 static void unicast_action_dispatch_disabled(
0077 uint32_t cpu_index,
0078 SMP_Action_handler handler,
0079 void *arg
0080 )
0081 {
0082 Per_CPU_Control *cpu_self;
0083
0084 cpu_self = _Thread_Dispatch_disable();
0085 _SMP_Unicast_action(cpu_index, handler, arg);
0086 _Thread_Dispatch_enable(cpu_self);
0087 }
0088
0089 static void multicast_action_irq_disabled(
0090 const Processor_mask *targets,
0091 SMP_Action_handler handler,
0092 void *arg
0093 )
0094 {
0095 rtems_interrupt_level level;
0096
0097 rtems_interrupt_local_disable(level);
0098 _SMP_Multicast_action(targets, handler, arg);
0099 rtems_interrupt_local_enable(level);
0100 }
0101
0102 static void multicast_action_dispatch_disabled(
0103 const Processor_mask *targets,
0104 SMP_Action_handler handler,
0105 void *arg
0106 )
0107 {
0108 Per_CPU_Control *cpu_self;
0109
0110 cpu_self = _Thread_Dispatch_disable();
0111 _SMP_Multicast_action(targets, handler, arg);
0112 _Thread_Dispatch_enable(cpu_self);
0113 }
0114
0115 static void broadcast_action_irq_disabled(
0116 SMP_Action_handler handler,
0117 void *arg
0118 )
0119 {
0120 rtems_interrupt_level level;
0121
0122 rtems_interrupt_local_disable(level);
0123 _SMP_Broadcast_action(handler, arg);
0124 rtems_interrupt_local_enable(level);
0125 }
0126
0127 static void broadcast_action_dispatch_disabled(
0128 SMP_Action_handler handler,
0129 void *arg
0130 )
0131 {
0132 Per_CPU_Control *cpu_self;
0133
0134 cpu_self = _Thread_Dispatch_disable();
0135 _SMP_Broadcast_action(handler, arg);
0136 _Thread_Dispatch_enable(cpu_self);
0137 }
0138
0139 static void action(void *arg)
0140 {
0141 Atomic_Uint *id;
0142 uint32_t self;
0143 unsigned expected;
0144 bool success;
0145
0146 id = arg;
0147 self = rtems_scheduler_get_processor();
0148 expected = 0;
0149 success = _Atomic_Compare_exchange_uint(
0150 &id[self],
0151 &expected,
0152 self + 1,
0153 ATOMIC_ORDER_RELAXED,
0154 ATOMIC_ORDER_RELAXED
0155 );
0156 T_quiet_true(success, "set CPU identifier failed");
0157 }
0158
0159 static void test_unicast(
0160 test_context *ctx,
0161 void (*unicast_action)(uint32_t, SMP_Action_handler, void *)
0162 )
0163 {
0164 uint32_t step;
0165 uint32_t i;
0166 uint32_t n;
0167
0168 T_plan(1);
0169 step = 0;
0170 n = rtems_scheduler_get_processor_maximum();
0171
0172 for (i = 0; i < n; ++i) {
0173 uint32_t j;
0174
0175 clear_ids_by_worker(ctx, 0);
0176
0177 (*unicast_action)(i, action, &ctx->id[0][0]);
0178
0179 for (j = 0; j < n; ++j) {
0180 unsigned id;
0181
0182 ++step;
0183 id = _Atomic_Load_uint(&ctx->id[0][j], ATOMIC_ORDER_RELAXED);
0184
0185 if (j == i) {
0186 T_quiet_eq_uint(j + 1, id);
0187 } else {
0188 T_quiet_eq_uint(0, id);
0189 }
0190 }
0191 }
0192
0193 T_step_eq_u32(0, step, n * n);
0194 }
0195
0196 static void test_multicast(
0197 test_context *ctx,
0198 void (*multicast_action)(const Processor_mask *, SMP_Action_handler, void *)
0199 )
0200 {
0201 uint32_t step;
0202 uint32_t i;
0203 uint32_t n;
0204
0205 T_plan(1);
0206 step = 0;
0207 n = rtems_scheduler_get_processor_maximum();
0208
0209 for (i = 0; i < n; ++i) {
0210 Processor_mask cpus;
0211 uint32_t j;
0212
0213 clear_ids_by_worker(ctx, 0);
0214
0215 _Processor_mask_Zero(&cpus);
0216 _Processor_mask_Set(&cpus, i);
0217 (*multicast_action)(&cpus, action, &ctx->id[0][0]);
0218
0219 for (j = 0; j < n; ++j) {
0220 unsigned id;
0221
0222 ++step;
0223 id = _Atomic_Load_uint(&ctx->id[0][j], ATOMIC_ORDER_RELAXED);
0224
0225 if (j == i) {
0226 T_quiet_eq_uint(j + 1, id);
0227 } else {
0228 T_quiet_eq_uint(0, id);
0229 }
0230 }
0231 }
0232
0233 T_step_eq_u32(0, step, n * n);
0234 }
0235
0236 static void test_broadcast(
0237 test_context *ctx,
0238 void (*broadcast_action)(SMP_Action_handler, void *)
0239 )
0240 {
0241 uint32_t step;
0242 uint32_t i;
0243 uint32_t n;
0244
0245 T_plan(1);
0246 step = 0;
0247 n = rtems_scheduler_get_processor_maximum();
0248
0249 for (i = 0; i < n; ++i) {
0250 uint32_t j;
0251
0252 clear_ids_by_worker(ctx, 0);
0253
0254 (*broadcast_action)(action, &ctx->id[0][0]);
0255
0256 for (j = 0; j < n; ++j) {
0257 unsigned id;
0258
0259 ++step;
0260 id = _Atomic_Load_uint(&ctx->id[0][j], ATOMIC_ORDER_RELAXED);
0261 T_quiet_eq_uint(j + 1, id);
0262 }
0263 }
0264
0265 T_step_eq_u32(0, step, n * n);
0266 }
0267
0268 static rtems_interval test_duration(void)
0269 {
0270 return rtems_clock_get_ticks_per_second();
0271 }
0272
0273 static rtems_interval test_broadcast_init(
0274 rtems_test_parallel_context *base,
0275 void *arg,
0276 size_t active_workers
0277 )
0278 {
0279 return test_duration();
0280 }
0281
0282 static void test_broadcast_body(
0283 rtems_test_parallel_context *base,
0284 void *arg,
0285 size_t active_workers,
0286 size_t worker_index
0287 )
0288 {
0289 test_context *ctx;
0290
0291 ctx = (test_context *) base;
0292
0293 while (!rtems_test_parallel_stop_job(&ctx->base)) {
0294 Per_CPU_Control *cpu_self;
0295
0296 clear_ids_by_worker(ctx, worker_index);
0297 cpu_self = _Thread_Dispatch_disable();
0298 _SMP_Broadcast_action(action, &ctx->id[worker_index][0]);
0299 _Thread_Dispatch_enable(cpu_self);
0300 }
0301 }
0302
0303 static void test_broadcast_fini(
0304 rtems_test_parallel_context *base,
0305 void *arg,
0306 size_t active_workers
0307 )
0308 {
0309
0310 }
0311
0312 static const rtems_test_parallel_job test_jobs[] = {
0313 {
0314 .init = test_broadcast_init,
0315 .body = test_broadcast_body,
0316 .fini = test_broadcast_fini,
0317 .cascade = true
0318 }
0319 };
0320
0321 T_TEST_CASE(ParallelBroadcast)
0322 {
0323 rtems_test_parallel(
0324 &test_instance.base,
0325 NULL,
0326 &test_jobs[0],
0327 RTEMS_ARRAY_SIZE(test_jobs)
0328 );
0329 }
0330
0331 static void test_before_multitasking(void)
0332 {
0333 test_context *ctx;
0334
0335 ctx = &test_instance;
0336
0337 T_case_begin("UnicastBeforeMultitasking", NULL);
0338 test_unicast(ctx, _SMP_Unicast_action);
0339 T_case_end();
0340
0341 T_case_begin("UnicastBeforeMultitaskingIRQDisabled", NULL);
0342 test_unicast(ctx, unicast_action_irq_disabled);
0343 T_case_end();
0344
0345 T_case_begin("UnicastBeforeMultitaskingDispatchDisabled", NULL);
0346 test_unicast(ctx, unicast_action_dispatch_disabled);
0347 T_case_end();
0348
0349 T_case_begin("MulticastBeforeMultitasking", NULL);
0350 test_multicast(ctx, _SMP_Multicast_action);
0351 T_case_end();
0352
0353 T_case_begin("MulticastBeforeMultitaskingIRQDisabled", NULL);
0354 test_multicast(ctx, multicast_action_irq_disabled);
0355 T_case_end();
0356
0357 T_case_begin("MulticastBeforeMultitaskingDispatchDisabled", NULL);
0358 test_multicast(ctx, multicast_action_dispatch_disabled);
0359 T_case_end();
0360
0361 T_case_begin("BroadcastBeforeMultitasking", NULL);
0362 test_broadcast(ctx, _SMP_Broadcast_action);
0363 T_case_end();
0364
0365 T_case_begin("BroadcastBeforeMultitaskingIRQDisabled", NULL);
0366 test_broadcast(ctx, broadcast_action_irq_disabled);
0367 T_case_end();
0368
0369 T_case_begin("BroadcastBeforeMultitaskingDispatchDisabled", NULL);
0370 test_broadcast(ctx, broadcast_action_dispatch_disabled);
0371 T_case_end();
0372 }
0373
0374 static void after_drivers(void)
0375 {
0376 TEST_BEGIN();
0377 T_run_initialize(&config);
0378 test_before_multitasking();
0379 }
0380
0381 RTEMS_SYSINIT_ITEM(
0382 after_drivers,
0383 RTEMS_SYSINIT_DEVICE_DRIVERS,
0384 RTEMS_SYSINIT_ORDER_LAST
0385 );
0386
0387 static void set_wrong_cpu_state(void *arg)
0388 {
0389 Per_CPU_Control *cpu_self;
0390
0391 cpu_self = arg;
0392 T_step_eq_ptr(0, cpu_self, _Per_CPU_Get());
0393 _Per_CPU_Set_state(cpu_self, 123);
0394
0395 while (true) {
0396
0397 }
0398 }
0399
0400 static void test_wrong_cpu_state_to_perform_jobs(void)
0401 {
0402 Per_CPU_Control *cpu_self;
0403 rtems_interrupt_level level;
0404 Processor_mask targets;
0405 uint32_t cpu_index;
0406
0407 T_case_begin("WrongCPUStateToPerformJobs", NULL);
0408 T_plan(4);
0409 cpu_self = _Thread_Dispatch_disable();
0410
0411 cpu_index = _Per_CPU_Get_index(cpu_self);
0412 cpu_index = (cpu_index + 1) % rtems_scheduler_get_processor_maximum();
0413 _Processor_mask_Zero(&targets);
0414 _Processor_mask_Set(&targets, cpu_index);
0415
0416 rtems_interrupt_local_disable(level);
0417
0418 _SMP_Multicast_action(
0419 &targets,
0420 set_wrong_cpu_state,
0421 _Per_CPU_Get_by_index(cpu_index)
0422 );
0423
0424
0425 rtems_interrupt_local_enable(level);
0426 _Thread_Dispatch_enable(cpu_self);
0427 rtems_fatal(RTEMS_FATAL_SOURCE_APPLICATION, 0);
0428 }
0429
0430 #define TEST_JOB_ORDER_JOBS 3
0431
0432 static Per_CPU_Job job_order_jobs[TEST_JOB_ORDER_JOBS];
0433
0434 static void job_order_handler_0(void *arg)
0435 {
0436 T_step(1);
0437 }
0438
0439 static void job_order_handler_1(void *arg)
0440 {
0441 T_step(2);
0442 }
0443
0444 static void job_order_handler_2(void *arg)
0445 {
0446 T_step(3);
0447 }
0448
0449 static const Per_CPU_Job_context job_order_contexts[TEST_JOB_ORDER_JOBS] = {
0450 { .handler = job_order_handler_0 },
0451 { .handler = job_order_handler_1 },
0452 { .handler = job_order_handler_2 }
0453 };
0454
0455 T_TEST_CASE(JobOrder)
0456 {
0457 Per_CPU_Control *cpu_self;
0458 size_t i;
0459
0460 T_plan(4);
0461 cpu_self = _Thread_Dispatch_disable();
0462
0463 for (i = 0; i < TEST_JOB_ORDER_JOBS; ++i) {
0464 job_order_jobs[i].context = &job_order_contexts[i];
0465 _Per_CPU_Add_job(cpu_self, &job_order_jobs[i]);
0466 }
0467
0468 T_step(0);
0469 _SMP_Send_message(cpu_self, SMP_MESSAGE_PERFORM_JOBS);
0470 _Thread_Dispatch_enable(cpu_self);
0471 }
0472
0473 #define TEST_ADD_JOB_IN_JOB_JOBS 3
0474
0475 static Per_CPU_Job add_job_in_job_jobs[TEST_ADD_JOB_IN_JOB_JOBS];
0476
0477 static void add_job_in_job_handler_0(void *arg)
0478 {
0479 T_step(1);
0480 _Per_CPU_Add_job(_Per_CPU_Get(), &add_job_in_job_jobs[1]);
0481 }
0482
0483 static void add_job_in_job_handler_1(void *arg)
0484 {
0485 T_step(3);
0486 }
0487
0488 static const Per_CPU_Job_context
0489 add_job_in_job_contexts[TEST_ADD_JOB_IN_JOB_JOBS] = {
0490 { .handler = add_job_in_job_handler_0 },
0491 { .handler = add_job_in_job_handler_1 }
0492 };
0493
0494 T_TEST_CASE(AddJobInJob)
0495 {
0496 Per_CPU_Control *cpu_self;
0497 size_t i;
0498
0499 T_plan(4);
0500 cpu_self = _Thread_Dispatch_disable();
0501
0502 for (i = 0; i < TEST_ADD_JOB_IN_JOB_JOBS; ++i) {
0503 add_job_in_job_jobs[i].context = &add_job_in_job_contexts[i];
0504 }
0505
0506 _Per_CPU_Add_job(cpu_self, &add_job_in_job_jobs[0]);
0507 T_step(0);
0508 _SMP_Send_message(cpu_self, SMP_MESSAGE_PERFORM_JOBS);
0509 _Per_CPU_Wait_for_job(cpu_self, &add_job_in_job_jobs[0]);
0510 T_step(2);
0511 _SMP_Send_message(cpu_self, SMP_MESSAGE_PERFORM_JOBS);
0512 _Thread_Dispatch_enable(cpu_self);
0513 }
0514
0515 T_TEST_CASE(UnicastDuringMultitaskingIRQDisabled)
0516 {
0517 test_unicast(&test_instance, unicast_action_irq_disabled);
0518 }
0519
0520 T_TEST_CASE(UnicastDuringMultitaskingDispatchDisabled)
0521 {
0522 test_unicast(&test_instance, unicast_action_dispatch_disabled);
0523 }
0524
0525 T_TEST_CASE(MulticastDuringMultitaskingIRQDisabled)
0526 {
0527 test_multicast(&test_instance, multicast_action_irq_disabled);
0528 }
0529
0530 T_TEST_CASE(MulticastDuringMultitaskingDispatchDisabled)
0531 {
0532 test_multicast(&test_instance, multicast_action_dispatch_disabled);
0533 }
0534
0535 T_TEST_CASE(BroadcastDuringMultitaskingIRQDisabled)
0536 {
0537 test_broadcast(&test_instance, broadcast_action_irq_disabled);
0538 }
0539
0540 T_TEST_CASE(BroadcastDuringMultitaskingDispatchDisabled)
0541 {
0542 test_broadcast(&test_instance, broadcast_action_dispatch_disabled);
0543 }
0544
0545 static void Init(rtems_task_argument arg)
0546 {
0547 T_register();
0548 T_run_all();
0549
0550 if (rtems_scheduler_get_processor_maximum() > 1) {
0551 test_wrong_cpu_state_to_perform_jobs();
0552 } else {
0553 rtems_fatal(RTEMS_FATAL_SOURCE_APPLICATION, 0);
0554 }
0555 }
0556
0557 static void fatal_extension(
0558 rtems_fatal_source source,
0559 bool always_set_to_false,
0560 rtems_fatal_code code
0561 )
0562 {
0563 bool ok;
0564
0565 if (source == RTEMS_FATAL_SOURCE_SMP) {
0566 if (code != SMP_FATAL_SHUTDOWN_RESPONSE) {
0567 T_step_eq_int(1, source, RTEMS_FATAL_SOURCE_SMP);
0568 T_step_false(2, always_set_to_false, "unexpected argument value");
0569 T_step_eq_int(3, code, SMP_FATAL_WRONG_CPU_STATE_TO_PERFORM_JOBS);
0570 T_case_end();
0571
0572 ok = T_run_finalize();
0573 rtems_test_assert(ok);
0574 TEST_END();
0575 }
0576 } else if (source == RTEMS_FATAL_SOURCE_APPLICATION) {
0577 ok = T_run_finalize();
0578 rtems_test_assert(ok);
0579 TEST_END();
0580 }
0581 }
0582
0583 #define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
0584
0585 #define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
0586
0587 #define CONFIGURE_MAXIMUM_TIMERS 1
0588
0589 #define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
0590
0591 #define CONFIGURE_INITIAL_EXTENSIONS \
0592 { .fatal = fatal_extension }, \
0593 RTEMS_TEST_INITIAL_EXTENSION
0594
0595 #define CONFIGURE_RTEMS_INIT_TASKS_TABLE
0596
0597 #define CONFIGURE_INIT
0598
0599 #include <rtems/confdefs.h>