source: rtems/testsuites/smptests/smpatomic01/init.c @ e644155a

4.115
Last change on this file since e644155a was 945853b7, checked in by Sebastian Huber <sebastian.huber@…>, on 02/13/14 at 14:38:52

score: Add Atomic_Uint

  • Property mode set to 100644
File size: 15.9 KB
Line 
1/*
2 * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * Copyright (c) 2013 Deng Hengyi.
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.com/license/LICENSE.
15 */
16
17#ifdef HAVE_CONFIG_H
18  #include "config.h"
19#endif
20
21#include <rtems/score/atomic.h>
22#include <rtems.h>
23#include <string.h>
24
25#include "tmacros.h"
26
27/* FIXME: Add barrier to Score */
28
29typedef struct {
30        Atomic_Ulong value;
31        Atomic_Ulong sense;
32} SMP_barrier_Control;
33
34typedef struct {
35        unsigned long sense;
36} SMP_barrier_State;
37
38#define SMP_BARRIER_CONTROL_INITIALIZER \
39  { ATOMIC_INITIALIZER_ULONG( 0 ), ATOMIC_INITIALIZER_ULONG( 0 ) }
40
41#define SMP_BARRIER_STATE_INITIALIZER { 0 }
42
43static void _SMP_barrier_Wait(
44  SMP_barrier_Control *control,
45  SMP_barrier_State *state,
46  unsigned long count
47)
48{
49  unsigned long sense = ~state->sense;
50  unsigned long previous_value;
51
52  state->sense = sense;
53
54  previous_value = _Atomic_Fetch_add_ulong(
55    &control->value,
56    1,
57    ATOMIC_ORDER_RELAXED
58  );
59
60  if ( previous_value + 1 == count ) {
61    _Atomic_Store_ulong( &control->value, 0, ATOMIC_ORDER_RELAXED );
62    _Atomic_Store_ulong( &control->sense, sense, ATOMIC_ORDER_RELEASE );
63  } else {
64    while (
65      _Atomic_Load_ulong( &control->sense, ATOMIC_ORDER_ACQUIRE ) != sense
66    ) {
67      /* Wait */
68    }
69  }
70}
71
72#define MASTER_PRIORITY 1
73
74#define WORKER_PRIORITY 2
75
76#define CPU_COUNT 32
77
78typedef struct {
79  Atomic_Ulong stop;
80  SMP_barrier_Control barrier;
81  size_t worker_count;
82  rtems_id stop_worker_timer_id;
83  Atomic_Uint atomic_int_value;
84  Atomic_Ulong atomic_value;
85  unsigned long per_worker_value[CPU_COUNT];
86  unsigned long normal_value;
87  Atomic_Flag global_flag;
88} test_context;
89
90typedef struct {
91  void (*init)(test_context *ctx);
92  void (*body)(test_context *ctx, size_t worker_index);
93  void (*fini)(test_context *ctx);
94} test_case;
95
96static test_context test_instance = {
97  .stop = ATOMIC_INITIALIZER_ULONG(0),
98  .barrier = SMP_BARRIER_CONTROL_INITIALIZER
99};
100
101static bool stop(test_context *ctx)
102{
103  return _Atomic_Load_ulong(&ctx->stop, ATOMIC_ORDER_RELAXED) != 0;
104}
105
106static bool is_master_worker(size_t worker_index)
107{
108  return worker_index == 0;
109}
110
111static void test_fini(
112  test_context *ctx,
113  const char *test,
114  bool atomic
115)
116{
117  unsigned long expected_value = 0;
118  unsigned long actual_value;
119  size_t worker_index;
120
121  printf("=== atomic %s test case ==\n", test);
122
123  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
124    unsigned long worker_value = ctx->per_worker_value[worker_index];
125
126    expected_value += worker_value;
127
128    printf(
129      "worker %zu value: %lu\n",
130      worker_index,
131      worker_value
132    );
133  }
134
135  if (atomic) {
136    actual_value = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
137  } else {
138    actual_value = ctx->normal_value;
139  }
140
141  printf(
142    "atomic value: expected = %lu, actual = %lu\n",
143    expected_value,
144    actual_value
145  );
146
147  rtems_test_assert(expected_value == actual_value);
148}
149
150static void test_atomic_add_init(test_context *ctx)
151{
152  _Atomic_Init_ulong(&ctx->atomic_value, 0);
153}
154
155static void test_atomic_add_body(test_context *ctx, size_t worker_index)
156{
157  unsigned long counter = 0;
158
159  while (!stop(ctx)) {
160    ++counter;
161    _Atomic_Fetch_add_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
162  }
163
164  ctx->per_worker_value[worker_index] = counter;
165}
166
167static void test_atomic_add_fini(test_context *ctx)
168{
169  test_fini(ctx, "add", true);
170}
171
172static void test_atomic_flag_init(test_context *ctx)
173{
174  _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
175  ctx->normal_value = 0;
176}
177
178static void test_atomic_flag_body(test_context *ctx, size_t worker_index)
179{
180  unsigned long counter = 0;
181
182  while (!stop(ctx)) {
183    while (_Atomic_Flag_test_and_set(&ctx->global_flag, ATOMIC_ORDER_ACQUIRE)) {
184      /* Wait */
185    }
186
187    ++counter;
188    ++ctx->normal_value;
189
190    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
191  }
192
193  ctx->per_worker_value[worker_index] = counter;
194}
195
196static void test_atomic_flag_fini(test_context *ctx)
197{
198  test_fini(ctx, "flag", false);
199}
200
201static void test_atomic_sub_init(test_context *ctx)
202{
203  _Atomic_Init_ulong(&ctx->atomic_value, 0);
204}
205
206static void test_atomic_sub_body(test_context *ctx, size_t worker_index)
207{
208  unsigned long counter = 0;
209
210  while (!stop(ctx)) {
211    --counter;
212    _Atomic_Fetch_sub_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
213  }
214
215  ctx->per_worker_value[worker_index] = counter;
216}
217
218static void test_atomic_sub_fini(test_context *ctx)
219{
220  test_fini(ctx, "sub", true);
221}
222
223static void test_atomic_compare_exchange_init(test_context *ctx)
224{
225  _Atomic_Init_ulong(&ctx->atomic_value, 0);
226  ctx->normal_value = 0;
227}
228
229static void test_atomic_compare_exchange_body(test_context *ctx, size_t worker_index)
230{
231  unsigned long counter = 0;
232
233  while (!stop(ctx)) {
234    bool success;
235
236    do {
237      unsigned long zero = 0;
238
239      success = _Atomic_Compare_exchange_ulong(
240        &ctx->atomic_value,
241        &zero,
242        1,
243        ATOMIC_ORDER_ACQUIRE,
244        ATOMIC_ORDER_RELAXED
245      );
246    } while (!success);
247
248    ++counter;
249    ++ctx->normal_value;
250
251    _Atomic_Store_ulong(&ctx->atomic_value, 0, ATOMIC_ORDER_RELEASE);
252  }
253
254  ctx->per_worker_value[worker_index] = counter;
255}
256
257static void test_atomic_compare_exchange_fini(test_context *ctx)
258{
259  test_fini(ctx, "compare exchange", false);
260}
261
262static void test_atomic_or_and_init(test_context *ctx)
263{
264  _Atomic_Init_ulong(&ctx->atomic_value, 0);
265}
266
267static void test_atomic_or_and_body(test_context *ctx, size_t worker_index)
268{
269  unsigned long the_bit = 1UL << worker_index;
270  unsigned long current_bit = 0;
271
272  while (!stop(ctx)) {
273    unsigned long previous;
274
275    if (current_bit != 0) {
276      previous = _Atomic_Fetch_and_ulong(
277        &ctx->atomic_value,
278        ~the_bit,
279        ATOMIC_ORDER_RELAXED
280      );
281      current_bit = 0;
282    } else {
283      previous = _Atomic_Fetch_or_ulong(
284        &ctx->atomic_value,
285        the_bit,
286        ATOMIC_ORDER_RELAXED
287      );
288      current_bit = the_bit;
289    }
290
291    rtems_test_assert((previous & the_bit) != current_bit);
292  }
293
294  ctx->per_worker_value[worker_index] = current_bit;
295}
296
297static void test_atomic_or_and_fini(test_context *ctx)
298{
299  test_fini(ctx, "or/and", true);
300}
301
302static const test_case test_cases[] = {
303  {
304    test_atomic_add_init,
305    test_atomic_add_body,
306    test_atomic_add_fini
307  }, {
308    test_atomic_flag_init,
309    test_atomic_flag_body,
310    test_atomic_flag_fini
311  }, {
312    test_atomic_sub_init,
313    test_atomic_sub_body,
314    test_atomic_sub_fini
315  }, {
316    test_atomic_compare_exchange_init,
317    test_atomic_compare_exchange_body,
318    test_atomic_compare_exchange_fini
319  }, {
320    test_atomic_or_and_init,
321    test_atomic_or_and_body,
322    test_atomic_or_and_fini
323  },
324};
325
326#define TEST_COUNT RTEMS_ARRAY_SIZE(test_cases)
327
328static void stop_worker_timer(rtems_id timer_id, void *arg)
329{
330  test_context *ctx = arg;
331
332  _Atomic_Store_ulong(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
333}
334
335static void start_worker_stop_timer(test_context *ctx)
336{
337  rtems_status_code sc;
338
339  _Atomic_Store_ulong(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
340
341  sc = rtems_timer_fire_after(
342    ctx->stop_worker_timer_id,
343    rtems_clock_get_ticks_per_second(),
344    stop_worker_timer,
345    ctx
346  );
347  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
348}
349
350static void run_tests(test_context *ctx, size_t worker_index)
351{
352  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
353  size_t test;
354
355  for (test = 0; test < TEST_COUNT; ++test) {
356    const test_case *tc = &test_cases[test];
357
358    if (is_master_worker(worker_index)) {
359      start_worker_stop_timer(ctx);
360      (*tc->init)(ctx);
361    }
362
363    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
364
365    (*tc->body)(ctx, worker_index);
366
367    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
368
369    if (is_master_worker(worker_index)) {
370      (*tc->fini)(ctx);
371    }
372  }
373}
374
375static void worker_task(size_t worker_index)
376{
377  test_context *ctx = &test_instance;
378
379  run_tests(ctx, worker_index);
380
381  (void) rtems_task_suspend(RTEMS_SELF);
382  rtems_test_assert(0);
383}
384
385static void test_static_and_dynamic_initialization(void)
386{
387  static Atomic_Uint static_uint =
388    ATOMIC_INITIALIZER_UINT(0xc01dc0feU);
389  static Atomic_Ulong static_ulong =
390    ATOMIC_INITIALIZER_ULONG(0xdeadbeefUL);
391  static Atomic_Pointer static_ptr =
392    ATOMIC_INITIALIZER_PTR(&static_ptr);
393  static Atomic_Flag static_flag = ATOMIC_INITIALIZER_FLAG;
394
395  Atomic_Uint stack_uint;
396  Atomic_Ulong stack_ulong;
397  Atomic_Pointer stack_ptr;
398  Atomic_Flag stack_flag;
399
400  puts("=== static and dynamic initialization test case ===");
401
402  _Atomic_Init_uint(&stack_uint, 0xc01dc0feU);
403  _Atomic_Init_ulong(&stack_ulong, 0xdeadbeefUL);
404  _Atomic_Init_ptr(&stack_ptr, &static_ptr);
405  _Atomic_Flag_clear(&stack_flag, ATOMIC_ORDER_RELAXED);
406
407  rtems_test_assert(
408    memcmp(&stack_uint, &static_uint, sizeof(stack_uint)) == 0
409  );
410  rtems_test_assert(
411    memcmp(&stack_ulong, &static_ulong, sizeof(stack_ulong)) == 0
412  );
413  rtems_test_assert(
414    memcmp(&stack_ptr, &static_ptr, sizeof(stack_ptr)) == 0
415  );
416  rtems_test_assert(
417    memcmp(&stack_flag, &static_flag, sizeof(stack_flag)) == 0
418  );
419
420  rtems_test_assert(
421    _Atomic_Load_uint(&stack_uint, ATOMIC_ORDER_RELAXED) == 0xc01dc0feU
422  );
423  rtems_test_assert(
424    _Atomic_Load_ulong(&stack_ulong, ATOMIC_ORDER_RELAXED) == 0xdeadbeefUL
425  );
426  rtems_test_assert(
427    _Atomic_Load_ptr(&stack_ptr, ATOMIC_ORDER_RELAXED) == &static_ptr
428  );
429  rtems_test_assert(
430    !_Atomic_Flag_test_and_set(&stack_flag, ATOMIC_ORDER_RELAXED)
431  );
432}
433
434static void test(void)
435{
436  test_context *ctx = &test_instance;
437  rtems_status_code sc;
438  size_t worker_index;
439
440  test_static_and_dynamic_initialization();
441
442  ctx->worker_count = rtems_smp_get_processor_count();
443
444  sc = rtems_timer_create(
445    rtems_build_name('S', 'T', 'O', 'P'),
446    &ctx->stop_worker_timer_id
447  );
448  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
449
450  for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
451    rtems_id worker_id;
452
453    sc = rtems_task_create(
454      rtems_build_name('W', 'O', 'R', 'K'),
455      WORKER_PRIORITY,
456      RTEMS_MINIMUM_STACK_SIZE,
457      RTEMS_DEFAULT_MODES,
458      RTEMS_DEFAULT_ATTRIBUTES,
459      &worker_id
460    );
461    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
462
463    sc = rtems_task_start(worker_id, worker_task, worker_index);
464    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
465  }
466
467  run_tests(ctx, 0);
468}
469
470typedef void (*simple_test_body)(test_context *ctx);
471
472static void test_simple_atomic_add_body(test_context *ctx)
473{
474  unsigned int ia = 8, ib = 4;
475  unsigned int ic;
476  unsigned long a = 2, b = 1;
477  unsigned long c;
478
479  puts("=== atomic simple add test case ==\n");
480
481  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
482  _Atomic_Fetch_add_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
483  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
484  rtems_test_assert(ic == (ia + ib));
485
486  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
487  _Atomic_Fetch_add_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
488  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
489  rtems_test_assert(c == (a + b));
490}
491
492static void test_simple_atomic_sub_body(test_context *ctx)
493{
494  unsigned int ia = 8, ib = 4;
495  unsigned int ic;
496  unsigned long a = 2, b = 1;
497  unsigned long c;
498
499  puts("=== atomic simple sub test case ==\n");
500
501  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
502  _Atomic_Fetch_sub_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
503  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
504  rtems_test_assert(ic == (ia - ib));
505
506  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
507  _Atomic_Fetch_sub_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
508  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
509  rtems_test_assert(c == (a - b));
510}
511
512static void test_simple_atomic_or_body(test_context *ctx)
513{
514  unsigned int ia = 8, ib = 4;
515  unsigned int ic;
516  unsigned long a = 2, b = 1;
517  unsigned long c;
518
519  puts("=== atomic simple or test case ==\n");
520
521  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
522  _Atomic_Fetch_or_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
523  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
524  rtems_test_assert(ic == (ia | ib));
525
526  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
527  _Atomic_Fetch_or_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
528  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
529  rtems_test_assert(c == (a | b));
530}
531
532static void test_simple_atomic_and_body(test_context *ctx)
533{
534  unsigned int ia = 8, ib = 4;
535  unsigned int ic;
536  unsigned long a = 2, b = 1;
537  unsigned long c;
538
539  puts("=== atomic simple and test case ==\n");
540
541  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
542  _Atomic_Fetch_and_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
543  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
544  rtems_test_assert(ic == (ia & ib));
545
546  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
547  _Atomic_Fetch_and_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
548  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
549  rtems_test_assert(c == (a & b));
550}
551
552static void test_simple_atomic_exchange_body(test_context *ctx)
553{
554  unsigned int ia = 8, ib = 4;
555  unsigned int ic;
556  unsigned long a = 2, b = 1;
557  unsigned long c;
558
559  puts("=== atomic simple exchange test case ==\n");
560
561  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
562  _Atomic_Exchange_uint(&ctx->atomic_int_value, ib, ATOMIC_ORDER_RELAXED);
563  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
564  rtems_test_assert(ic == ib);
565
566  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
567  _Atomic_Exchange_ulong(&ctx->atomic_value, b, ATOMIC_ORDER_RELAXED);
568  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
569  rtems_test_assert(c == b);
570}
571
572static void test_simple_atomic_compare_exchange_body(test_context *ctx)
573{
574  unsigned int ia = 8, ib = 4;
575  unsigned int ic;
576  unsigned long a = 2, b = 1;
577  unsigned long c;
578
579  puts("=== atomic simple compare exchange test case ==\n");
580
581  _Atomic_Store_uint(&ctx->atomic_int_value, ia, ATOMIC_ORDER_RELAXED);
582  _Atomic_Compare_exchange_uint(&ctx->atomic_int_value, &ia, ib,
583    ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
584  ic = _Atomic_Load_uint(&ctx->atomic_int_value, ATOMIC_ORDER_RELAXED);
585  rtems_test_assert(ic == ib);
586
587  _Atomic_Store_ulong(&ctx->atomic_value, a, ATOMIC_ORDER_RELAXED);
588  _Atomic_Compare_exchange_ulong(&ctx->atomic_value, &a, b,
589    ATOMIC_ORDER_RELAXED, ATOMIC_ORDER_RELAXED);
590  c = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
591  rtems_test_assert(c == b);
592}
593
594static const simple_test_body simple_test_bodies[] = {
595  test_simple_atomic_add_body,
596  test_simple_atomic_sub_body,
597  test_simple_atomic_or_body,
598  test_simple_atomic_and_body,
599  test_simple_atomic_exchange_body,
600  test_simple_atomic_compare_exchange_body,
601};
602
603#define SIMPLE_TEST_COUNT RTEMS_ARRAY_SIZE(simple_test_bodies)
604
605static void simple_tests(void)
606{
607  test_context *ctx = &test_instance;
608  size_t test;
609
610  for (test = 0; test < SIMPLE_TEST_COUNT; ++test) {
611    const simple_test_body *test_body = &simple_test_bodies[test];
612
613    (*test_body)(ctx);
614  }
615}
616
617static void Init(rtems_task_argument arg)
618{
619  puts("\n\n*** TEST SMPATOMIC 1 ***");
620
621  simple_tests();
622
623  test();
624
625  puts("*** END OF TEST SMPATOMIC 1 ***");
626
627  rtems_test_exit(0);
628}
629
630#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
631#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
632
633#define CONFIGURE_SMP_APPLICATION
634
635#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
636
637#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
638
639#define CONFIGURE_MAXIMUM_TIMERS 1
640
641#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
642#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
643#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
644
645#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
646
647#define CONFIGURE_INIT
648
649#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.