Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:43

0001 /*
0002  * SPDX-License-Identifier: BSD-2-Clause
0003  *
0004  * Copyright (C) 2019 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
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   /* Do nothing */
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     /* Do nothing */
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   /* If everything is all right, we don't end up here */
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>