source: rtems/testsuites/smptests/smpmulticast01/init.c @ 2d8802b

Last change on this file since 2d8802b was 2d8802b, checked in by Sebastian Huber <sebastian.huber@…>, on 09/26/20 at 09:53:07

tests: Add and use <rtems/testopts.h>

Add the build option RTEMS_TEST_VERBOSITY to control the verbosity of
test suites using the RTEMS Test Framework.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2019 embedded brains GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <rtems/score/smpimpl.h>
29#include <rtems/score/atomic.h>
30#include <rtems/score/threaddispatch.h>
31#include <rtems/sysinit.h>
32#include <rtems.h>
33
34#include <string.h>
35
36#include <rtems/test.h>
37#include <rtems/testopts.h>
38#include <tmacros.h>
39
40#define CPU_COUNT 32
41
42const char rtems_test_name[] = "SMPMULTICAST 1";
43
44static const T_config config = {
45  .name = "SMPMultiCast",
46  .putchar = T_putchar_default,
47  .verbosity = RTEMS_TEST_VERBOSITY,
48  .now = T_now_clock
49};
50
51typedef struct {
52  rtems_test_parallel_context base;
53  Atomic_Uint id[CPU_COUNT][CPU_COUNT];
54} test_context;
55
56static test_context test_instance;
57
58static void clear_ids_by_worker(test_context *ctx, size_t worker_index)
59{
60  memset(&ctx->id[worker_index][0], 0, sizeof(ctx->id[worker_index]));
61}
62
63static void unicast_action_irq_disabled(
64  uint32_t cpu_index,
65  SMP_Action_handler handler,
66  void *arg
67)
68{
69  rtems_interrupt_level level;
70
71  rtems_interrupt_local_disable(level);
72  _SMP_Unicast_action(cpu_index, handler, arg);
73  rtems_interrupt_local_enable(level);
74}
75
76static void unicast_action_dispatch_disabled(
77  uint32_t cpu_index,
78  SMP_Action_handler handler,
79  void *arg
80)
81{
82  Per_CPU_Control *cpu_self;
83
84  cpu_self = _Thread_Dispatch_disable();
85  _SMP_Unicast_action(cpu_index, handler, arg);
86  _Thread_Dispatch_enable(cpu_self);
87}
88
89static void multicast_action_irq_disabled(
90  const Processor_mask *targets,
91  SMP_Action_handler handler,
92  void *arg
93)
94{
95  rtems_interrupt_level level;
96
97  rtems_interrupt_local_disable(level);
98  _SMP_Multicast_action(targets, handler, arg);
99  rtems_interrupt_local_enable(level);
100}
101
102static void multicast_action_dispatch_disabled(
103  const Processor_mask *targets,
104  SMP_Action_handler handler,
105  void *arg
106)
107{
108  Per_CPU_Control *cpu_self;
109
110  cpu_self = _Thread_Dispatch_disable();
111  _SMP_Multicast_action(targets, handler, arg);
112  _Thread_Dispatch_enable(cpu_self);
113}
114
115static void broadcast_action_irq_disabled(
116  SMP_Action_handler handler,
117  void *arg
118)
119{
120  rtems_interrupt_level level;
121
122  rtems_interrupt_local_disable(level);
123  _SMP_Broadcast_action(handler, arg);
124  rtems_interrupt_local_enable(level);
125}
126
127static void broadcast_action_dispatch_disabled(
128  SMP_Action_handler handler,
129  void *arg
130)
131{
132  Per_CPU_Control *cpu_self;
133
134  cpu_self = _Thread_Dispatch_disable();
135  _SMP_Broadcast_action(handler, arg);
136  _Thread_Dispatch_enable(cpu_self);
137}
138
139static void action(void *arg)
140{
141  Atomic_Uint *id;
142  uint32_t self;
143  unsigned expected;
144  bool success;
145
146  id = arg;
147  self = rtems_scheduler_get_processor();
148  expected = 0;
149  success = _Atomic_Compare_exchange_uint(
150    &id[self],
151    &expected,
152    self + 1,
153    ATOMIC_ORDER_RELAXED,
154    ATOMIC_ORDER_RELAXED
155  );
156  T_quiet_true(success, "set CPU identifier failed");
157}
158
159static void test_unicast(
160  test_context *ctx,
161  void (*unicast_action)(uint32_t, SMP_Action_handler, void *)
162)
163{
164  uint32_t step;
165  uint32_t i;
166  uint32_t n;
167
168  T_plan(1);
169  step = 0;
170  n = rtems_scheduler_get_processor_maximum();
171
172  for (i = 0; i < n; ++i) {
173    uint32_t j;
174
175    clear_ids_by_worker(ctx, 0);
176
177    (*unicast_action)(i, action, &ctx->id[0][0]);
178
179    for (j = 0; j < n; ++j) {
180      unsigned id;
181
182      ++step;
183      id = _Atomic_Load_uint(&ctx->id[0][j], ATOMIC_ORDER_RELAXED);
184
185      if (j == i) {
186        T_quiet_eq_uint(j + 1, id);
187      } else {
188        T_quiet_eq_uint(0, id);
189      }
190    }
191  }
192
193  T_step_eq_u32(0, step, n * n);
194}
195
196static void test_multicast(
197  test_context *ctx,
198  void (*multicast_action)(const Processor_mask *, SMP_Action_handler, void *)
199)
200{
201  uint32_t step;
202  uint32_t i;
203  uint32_t n;
204
205  T_plan(1);
206  step = 0;
207  n = rtems_scheduler_get_processor_maximum();
208
209  for (i = 0; i < n; ++i) {
210    Processor_mask cpus;
211    uint32_t j;
212
213    clear_ids_by_worker(ctx, 0);
214
215    _Processor_mask_Zero(&cpus);
216    _Processor_mask_Set(&cpus, i);
217    (*multicast_action)(&cpus, action, &ctx->id[0][0]);
218
219    for (j = 0; j < n; ++j) {
220      unsigned id;
221
222      ++step;
223      id = _Atomic_Load_uint(&ctx->id[0][j], ATOMIC_ORDER_RELAXED);
224
225      if (j == i) {
226        T_quiet_eq_uint(j + 1, id);
227      } else {
228        T_quiet_eq_uint(0, id);
229      }
230    }
231  }
232
233  T_step_eq_u32(0, step, n * n);
234}
235
236static void test_broadcast(
237  test_context *ctx,
238  void (*broadcast_action)(SMP_Action_handler, void *)
239)
240{
241  uint32_t step;
242  uint32_t i;
243  uint32_t n;
244
245  T_plan(1);
246  step = 0;
247  n = rtems_scheduler_get_processor_maximum();
248
249  for (i = 0; i < n; ++i) {
250    uint32_t j;
251
252    clear_ids_by_worker(ctx, 0);
253
254    (*broadcast_action)(action, &ctx->id[0][0]);
255
256    for (j = 0; j < n; ++j) {
257      unsigned id;
258
259      ++step;
260      id = _Atomic_Load_uint(&ctx->id[0][j], ATOMIC_ORDER_RELAXED);
261      T_quiet_eq_uint(j + 1, id);
262    }
263  }
264
265  T_step_eq_u32(0, step, n * n);
266}
267
268static rtems_interval test_duration(void)
269{
270  return rtems_clock_get_ticks_per_second();
271}
272
273static rtems_interval test_broadcast_init(
274  rtems_test_parallel_context *base,
275  void *arg,
276  size_t active_workers
277)
278{
279  return test_duration();
280}
281
282static void test_broadcast_body(
283  rtems_test_parallel_context *base,
284  void *arg,
285  size_t active_workers,
286  size_t worker_index
287)
288{
289  test_context *ctx;
290
291  ctx = (test_context *) base;
292
293  while (!rtems_test_parallel_stop_job(&ctx->base)) {
294    Per_CPU_Control *cpu_self;
295
296    clear_ids_by_worker(ctx, worker_index);
297    cpu_self = _Thread_Dispatch_disable();
298    _SMP_Multicast_action(NULL, action, &ctx->id[worker_index][0]);
299    _Thread_Dispatch_enable(cpu_self);
300  }
301}
302
303static void test_broadcast_fini(
304  rtems_test_parallel_context *base,
305  void *arg,
306  size_t active_workers
307)
308{
309  /* Do nothing */
310}
311
312static const rtems_test_parallel_job test_jobs[] = {
313  {
314    .init = test_broadcast_init,
315    .body = test_broadcast_body,
316    .fini = test_broadcast_fini,
317    .cascade = true
318  }
319};
320
321T_TEST_CASE(ParallelBroadcast)
322{
323  rtems_test_parallel(
324    &test_instance.base,
325    NULL,
326    &test_jobs[0],
327    RTEMS_ARRAY_SIZE(test_jobs)
328  );
329}
330
331static void test_before_multitasking(void)
332{
333  test_context *ctx;
334
335  ctx = &test_instance;
336
337  T_case_begin("UnicastBeforeMultitasking", NULL);
338  test_unicast(ctx, _SMP_Unicast_action);
339  T_case_end();
340
341  T_case_begin("UnicastBeforeMultitaskingIRQDisabled", NULL);
342  test_unicast(ctx, unicast_action_irq_disabled);
343  T_case_end();
344
345  T_case_begin("UnicastBeforeMultitaskingDispatchDisabled", NULL);
346  test_unicast(ctx, unicast_action_dispatch_disabled);
347  T_case_end();
348
349  T_case_begin("MulticastBeforeMultitasking", NULL);
350  test_multicast(ctx, _SMP_Multicast_action);
351  T_case_end();
352
353  T_case_begin("MulticastBeforeMultitaskingIRQDisabled", NULL);
354  test_multicast(ctx, multicast_action_irq_disabled);
355  T_case_end();
356
357  T_case_begin("MulticastBeforeMultitaskingDispatchDisabled", NULL);
358  test_multicast(ctx, multicast_action_dispatch_disabled);
359  T_case_end();
360
361  T_case_begin("BroadcastBeforeMultitasking", NULL);
362  test_broadcast(ctx, _SMP_Broadcast_action);
363  T_case_end();
364
365  T_case_begin("BroadcastBeforeMultitaskingIRQDisabled", NULL);
366  test_broadcast(ctx, broadcast_action_irq_disabled);
367  T_case_end();
368
369  T_case_begin("BroadcastBeforeMultitaskingDispatchDisabled", NULL);
370  test_broadcast(ctx, broadcast_action_dispatch_disabled);
371  T_case_end();
372}
373
374static void after_drivers(void)
375{
376  TEST_BEGIN();
377  T_run_initialize(&config);
378  test_before_multitasking();
379}
380
381RTEMS_SYSINIT_ITEM(
382  after_drivers,
383  RTEMS_SYSINIT_DEVICE_DRIVERS,
384  RTEMS_SYSINIT_ORDER_LAST
385);
386
387static void set_wrong_cpu_state(void *arg)
388{
389  Per_CPU_Control *cpu_self;
390
391  cpu_self = arg;
392  T_step_eq_ptr(0, cpu_self, _Per_CPU_Get());
393  cpu_self->state = 123;
394
395  while (true) {
396    /* Do nothing */
397  }
398}
399
400static void test_wrong_cpu_state_to_perform_jobs(void)
401{
402  Per_CPU_Control *cpu_self;
403  rtems_interrupt_level level;
404  Processor_mask targets;
405  uint32_t cpu_index;
406
407  T_case_begin("WrongCPUStateToPerformJobs", NULL);
408  T_plan(4);
409  cpu_self = _Thread_Dispatch_disable();
410
411  cpu_index = _Per_CPU_Get_index(cpu_self);
412  cpu_index = (cpu_index + 1) % rtems_scheduler_get_processor_maximum();
413  _Processor_mask_Zero(&targets);
414  _Processor_mask_Set(&targets, cpu_index);
415
416  rtems_interrupt_local_disable(level);
417
418  _SMP_Multicast_action(
419    &targets,
420    set_wrong_cpu_state,
421    _Per_CPU_Get_by_index(cpu_index)
422  );
423
424  /* If everything is all right, we don't end up here */
425  rtems_interrupt_local_enable(level);
426  _Thread_Dispatch_enable(cpu_self);
427  rtems_fatal(RTEMS_FATAL_SOURCE_APPLICATION, 0);
428}
429
430#define TEST_JOB_ORDER_JOBS 3
431
432static Per_CPU_Job job_order_jobs[TEST_JOB_ORDER_JOBS];
433
434static void job_order_handler_0(void *arg)
435{
436  T_step(1);
437}
438
439static void job_order_handler_1(void *arg)
440{
441  T_step(2);
442}
443
444static void job_order_handler_2(void *arg)
445{
446  T_step(3);
447}
448
449static const Per_CPU_Job_context job_order_contexts[TEST_JOB_ORDER_JOBS] = {
450  { .handler = job_order_handler_0 },
451  { .handler = job_order_handler_1 },
452  { .handler = job_order_handler_2 }
453};
454
455T_TEST_CASE(JobOrder)
456{
457  Per_CPU_Control *cpu_self;
458  size_t i;
459
460  T_plan(4);
461  cpu_self = _Thread_Dispatch_disable();
462
463  for (i = 0; i < TEST_JOB_ORDER_JOBS; ++i) {
464    job_order_jobs[i].context = &job_order_contexts[i];
465    _Per_CPU_Add_job(cpu_self, &job_order_jobs[i]);
466  }
467
468  T_step(0);
469  _SMP_Send_message(_Per_CPU_Get_index(cpu_self), SMP_MESSAGE_PERFORM_JOBS);
470  _Thread_Dispatch_enable(cpu_self);
471}
472
473#define TEST_ADD_JOB_IN_JOB_JOBS 3
474
475static Per_CPU_Job add_job_in_job_jobs[TEST_ADD_JOB_IN_JOB_JOBS];
476
477static void add_job_in_job_handler_0(void *arg)
478{
479  T_step(1);
480  _Per_CPU_Add_job(_Per_CPU_Get(), &add_job_in_job_jobs[1]);
481}
482
483static void add_job_in_job_handler_1(void *arg)
484{
485  T_step(3);
486}
487
488static const Per_CPU_Job_context
489add_job_in_job_contexts[TEST_ADD_JOB_IN_JOB_JOBS] = {
490  { .handler = add_job_in_job_handler_0 },
491  { .handler = add_job_in_job_handler_1 }
492};
493
494T_TEST_CASE(AddJobInJob)
495{
496  Per_CPU_Control *cpu_self;
497  size_t i;
498
499  T_plan(4);
500  cpu_self = _Thread_Dispatch_disable();
501
502  for (i = 0; i < TEST_ADD_JOB_IN_JOB_JOBS; ++i) {
503    add_job_in_job_jobs[i].context = &add_job_in_job_contexts[i];
504  }
505
506  _Per_CPU_Add_job(cpu_self, &add_job_in_job_jobs[0]);
507  T_step(0);
508  _SMP_Send_message(_Per_CPU_Get_index(cpu_self), SMP_MESSAGE_PERFORM_JOBS);
509  T_step(2);
510  _SMP_Send_message(_Per_CPU_Get_index(cpu_self), SMP_MESSAGE_PERFORM_JOBS);
511  _Thread_Dispatch_enable(cpu_self);
512}
513
514T_TEST_CASE(UnicastDuringMultitaskingIRQDisabled)
515{
516  test_unicast(&test_instance, unicast_action_irq_disabled);
517}
518
519T_TEST_CASE(UnicastDuringMultitaskingDispatchDisabled)
520{
521  test_unicast(&test_instance, unicast_action_dispatch_disabled);
522}
523
524T_TEST_CASE(MulticastDuringMultitaskingIRQDisabled)
525{
526  test_multicast(&test_instance, multicast_action_irq_disabled);
527}
528
529T_TEST_CASE(MulticastDuringMultitaskingDispatchDisabled)
530{
531  test_multicast(&test_instance, multicast_action_dispatch_disabled);
532}
533
534T_TEST_CASE(BroadcastDuringMultitaskingIRQDisabled)
535{
536  test_broadcast(&test_instance, broadcast_action_irq_disabled);
537}
538
539T_TEST_CASE(BroadcastDuringMultitaskingDispatchDisabled)
540{
541  test_broadcast(&test_instance, broadcast_action_dispatch_disabled);
542}
543
544static void Init(rtems_task_argument arg)
545{
546  T_register();
547  T_run_all();
548
549  if (rtems_scheduler_get_processor_maximum() > 1) {
550    test_wrong_cpu_state_to_perform_jobs();
551  } else {
552    rtems_fatal(RTEMS_FATAL_SOURCE_APPLICATION, 0);
553  }
554}
555
556static void fatal_extension(
557  rtems_fatal_source source,
558  bool always_set_to_false,
559  rtems_fatal_code code
560)
561{
562  bool ok;
563
564  if (source == RTEMS_FATAL_SOURCE_SMP) {
565    T_step_eq_int(1, source, RTEMS_FATAL_SOURCE_SMP);
566    T_step_false(2, always_set_to_false, "unexpected argument value");
567    T_step_eq_int(3, code, SMP_FATAL_WRONG_CPU_STATE_TO_PERFORM_JOBS);
568    T_case_end();
569
570    ok = T_run_finalize();
571    rtems_test_assert(ok);
572    TEST_END();
573  } else if (source == RTEMS_FATAL_SOURCE_APPLICATION) {
574    ok = T_run_finalize();
575    rtems_test_assert(ok);
576    TEST_END();
577  }
578}
579
580#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
581
582#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
583
584#define CONFIGURE_MAXIMUM_TIMERS 1
585
586#define CONFIGURE_MAXIMUM_PROCESSORS CPU_COUNT
587
588#define CONFIGURE_INITIAL_EXTENSIONS \
589  { .fatal = fatal_extension }, \
590  RTEMS_TEST_INITIAL_EXTENSION
591
592#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
593
594#define CONFIGURE_INIT
595
596#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.