source: rtems/testsuites/smptests/smpatomic08/init.c @ 29f7d317

4.115
Last change on this file since 29f7d317 was 29f7d317, checked in by Sebastian Huber <sebastian.huber@…>, on 09/02/13 at 13:08:05

score: Use unsigned long for atomic integers

Use unsigned long instead of uint_fast32_t since C11 provides only a
ATOMIC_LONG_LOCK_FREE macro constant. This makes it also possible to
use properly typed integer literals like 123UL. It is now clear which
compatible type should be used for the atomic integer.

  • Property mode set to 100644
File size: 9.4 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 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.com/license/LICENSE.
13 */
14
15#ifdef HAVE_CONFIG_H
16  #include "config.h"
17#endif
18
19#include <rtems/score/atomic.h>
20#include <rtems.h>
21
22#include "tmacros.h"
23
24/* FIXME: Add barrier to Score */
25
26typedef struct {
27        Atomic_Ulong value;
28        Atomic_Ulong sense;
29} SMP_barrier_Control;
30
31typedef struct {
32        unsigned long sense;
33} SMP_barrier_State;
34
35#define SMP_BARRIER_CONTROL_INITIALIZER \
36  { ATOMIC_INITIALIZER_ULONG( 0 ), ATOMIC_INITIALIZER_ULONG( 0 ) }
37
38#define SMP_BARRIER_STATE_INITIALIZER { 0 }
39
40static void _SMP_barrier_Wait(
41  SMP_barrier_Control *control,
42  SMP_barrier_State *state,
43  unsigned long count
44)
45{
46  unsigned long sense = ~state->sense;
47  unsigned long previous_value;
48
49  state->sense = sense;
50
51  previous_value = _Atomic_Fetch_add_ulong(
52    &control->value,
53    1,
54    ATOMIC_ORDER_RELAXED
55  );
56
57  if ( previous_value + 1 == count ) {
58    _Atomic_Store_ulong( &control->value, 0, ATOMIC_ORDER_RELAXED );
59    _Atomic_Store_ulong( &control->sense, sense, ATOMIC_ORDER_RELEASE );
60  } else {
61    while (
62      _Atomic_Load_ulong( &control->sense, ATOMIC_ORDER_ACQUIRE ) != sense
63    ) {
64      /* Wait */
65    }
66  }
67}
68
69#define MASTER_PRIORITY 1
70
71#define WORKER_PRIORITY 2
72
73#define CPU_COUNT 32
74
75typedef struct {
76  Atomic_Ulong stop;
77  SMP_barrier_Control barrier;
78  size_t worker_count;
79  rtems_id stop_worker_timer_id;
80  Atomic_Ulong atomic_value;
81  unsigned long per_worker_value[CPU_COUNT];
82  unsigned long normal_value;
83  Atomic_Flag global_flag;
84} test_context;
85
86typedef struct {
87  void (*init)(test_context *ctx);
88  void (*body)(test_context *ctx, size_t worker_index);
89  void (*fini)(test_context *ctx);
90} test_case;
91
92static test_context test_instance = {
93  .stop = ATOMIC_INITIALIZER_ULONG(0),
94  .barrier = SMP_BARRIER_CONTROL_INITIALIZER
95};
96
97static bool stop(test_context *ctx)
98{
99  return _Atomic_Load_ulong(&ctx->stop, ATOMIC_ORDER_RELAXED) != 0;
100}
101
102static bool is_master_worker(size_t worker_index)
103{
104  return worker_index == 0;
105}
106
107static void test_fini(
108  test_context *ctx,
109  const char *test,
110  bool atomic
111)
112{
113  unsigned long expected_value = 0;
114  unsigned long actual_value;
115  size_t worker_index;
116
117  printf("=== atomic %s test case ==\n", test);
118
119  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
120    unsigned long worker_value = ctx->per_worker_value[worker_index];
121
122    expected_value += worker_value;
123
124    printf(
125      "worker %zu value: %lu\n",
126      worker_index,
127      worker_value
128    );
129  }
130
131  if (atomic) {
132    actual_value = _Atomic_Load_ulong(&ctx->atomic_value, ATOMIC_ORDER_RELAXED);
133  } else {
134    actual_value = ctx->normal_value;
135  }
136
137  printf(
138    "atomic value: expected = %lu, actual = %lu\n",
139    expected_value,
140    actual_value
141  );
142
143  rtems_test_assert(expected_value == actual_value);
144}
145
146static void test_atomic_add_init(test_context *ctx)
147{
148  _Atomic_Init_ulong(&ctx->atomic_value, 0);
149}
150
151static void test_atomic_add_body(test_context *ctx, size_t worker_index)
152{
153  unsigned long counter = 0;
154
155  while (!stop(ctx)) {
156    ++counter;
157    _Atomic_Fetch_add_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
158  }
159
160  ctx->per_worker_value[worker_index] = counter;
161}
162
163static void test_atomic_add_fini(test_context *ctx)
164{
165  test_fini(ctx, "add", true);
166}
167
168static void test_atomic_flag_init(test_context *ctx)
169{
170  _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
171  ctx->normal_value = 0;
172}
173
174static void test_atomic_flag_body(test_context *ctx, size_t worker_index)
175{
176  unsigned long counter = 0;
177
178  while (!stop(ctx)) {
179    while (_Atomic_Flag_test_and_set(&ctx->global_flag, ATOMIC_ORDER_ACQUIRE)) {
180      /* Wait */
181    }
182
183    ++counter;
184    ++ctx->normal_value;
185
186    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
187  }
188
189  ctx->per_worker_value[worker_index] = counter;
190}
191
192static void test_atomic_flag_fini(test_context *ctx)
193{
194  test_fini(ctx, "flag", false);
195}
196
197static void test_atomic_sub_init(test_context *ctx)
198{
199  _Atomic_Init_ulong(&ctx->atomic_value, 0);
200}
201
202static void test_atomic_sub_body(test_context *ctx, size_t worker_index)
203{
204  unsigned long counter = 0;
205
206  while (!stop(ctx)) {
207    --counter;
208    _Atomic_Fetch_sub_ulong(&ctx->atomic_value, 1, ATOMIC_ORDER_RELAXED);
209  }
210
211  ctx->per_worker_value[worker_index] = counter;
212}
213
214static void test_atomic_sub_fini(test_context *ctx)
215{
216  test_fini(ctx, "sub", true);
217}
218
219static void test_atomic_compare_exchange_init(test_context *ctx)
220{
221  _Atomic_Init_ulong(&ctx->atomic_value, 0);
222  ctx->normal_value = 0;
223}
224
225static void test_atomic_compare_exchange_body(test_context *ctx, size_t worker_index)
226{
227  unsigned long counter = 0;
228
229  while (!stop(ctx)) {
230    bool success;
231
232    do {
233      unsigned long zero = 0;
234
235      success = _Atomic_Compare_exchange_ulong(
236        &ctx->atomic_value,
237        &zero,
238        1,
239        ATOMIC_ORDER_ACQUIRE,
240        ATOMIC_ORDER_RELAXED
241      );
242    } while (!success);
243
244    ++counter;
245    ++ctx->normal_value;
246
247    _Atomic_Store_ulong(&ctx->atomic_value, 0, ATOMIC_ORDER_RELEASE);
248  }
249
250  ctx->per_worker_value[worker_index] = counter;
251}
252
253static void test_atomic_compare_exchange_fini(test_context *ctx)
254{
255  test_fini(ctx, "compare exchange", false);
256}
257
258static void test_atomic_or_and_init(test_context *ctx)
259{
260  _Atomic_Init_ulong(&ctx->atomic_value, 0);
261}
262
263static void test_atomic_or_and_body(test_context *ctx, size_t worker_index)
264{
265  unsigned long the_bit = 1UL << worker_index;
266  unsigned long current_bit = 0;
267
268  while (!stop(ctx)) {
269    unsigned long previous;
270
271    if (current_bit != 0) {
272      previous = _Atomic_Fetch_and_ulong(
273        &ctx->atomic_value,
274        ~the_bit,
275        ATOMIC_ORDER_RELAXED
276      );
277      current_bit = 0;
278    } else {
279      previous = _Atomic_Fetch_or_ulong(
280        &ctx->atomic_value,
281        the_bit,
282        ATOMIC_ORDER_RELAXED
283      );
284      current_bit = the_bit;
285    }
286
287    rtems_test_assert((previous & the_bit) != current_bit);
288  }
289
290  ctx->per_worker_value[worker_index] = current_bit;
291}
292
293static void test_atomic_or_and_fini(test_context *ctx)
294{
295  test_fini(ctx, "or/and", true);
296}
297
298static const test_case test_cases[] = {
299  {
300    test_atomic_add_init,
301    test_atomic_add_body,
302    test_atomic_add_fini
303  }, {
304    test_atomic_flag_init,
305    test_atomic_flag_body,
306    test_atomic_flag_fini
307  }, {
308    test_atomic_sub_init,
309    test_atomic_sub_body,
310    test_atomic_sub_fini
311  }, {
312    test_atomic_compare_exchange_init,
313    test_atomic_compare_exchange_body,
314    test_atomic_compare_exchange_fini
315  }, {
316    test_atomic_or_and_init,
317    test_atomic_or_and_body,
318    test_atomic_or_and_fini
319  },
320};
321
322#define TEST_COUNT RTEMS_ARRAY_SIZE(test_cases)
323
324static void stop_worker_timer(rtems_id timer_id, void *arg)
325{
326  test_context *ctx = arg;
327
328  _Atomic_Store_ulong(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
329}
330
331static void start_worker_stop_timer(test_context *ctx)
332{
333  rtems_status_code sc;
334
335  _Atomic_Store_ulong(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
336
337  sc = rtems_timer_fire_after(
338    ctx->stop_worker_timer_id,
339    rtems_clock_get_ticks_per_second(),
340    stop_worker_timer,
341    ctx
342  );
343  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
344}
345
346static void run_tests(test_context *ctx, size_t worker_index)
347{
348  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
349  size_t test;
350
351  for (test = 0; test < TEST_COUNT; ++test) {
352    const test_case *tc = &test_cases[test];
353
354    if (is_master_worker(worker_index)) {
355      start_worker_stop_timer(ctx);
356      (*tc->init)(ctx);
357    }
358
359    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
360
361    (*tc->body)(ctx, worker_index);
362
363    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
364
365    if (is_master_worker(worker_index)) {
366      (*tc->fini)(ctx);
367    }
368  }
369}
370
371static void worker_task(size_t worker_index)
372{
373  test_context *ctx = &test_instance;
374
375  run_tests(ctx, worker_index);
376
377  (void) rtems_task_suspend(RTEMS_SELF);
378  rtems_test_assert(0);
379}
380
381static void test(void)
382{
383  test_context *ctx = &test_instance;
384  rtems_status_code sc;
385  size_t worker_index;
386
387  ctx->worker_count = rtems_smp_get_processor_count();
388
389  sc = rtems_timer_create(
390    rtems_build_name('S', 'T', 'O', 'P'),
391    &ctx->stop_worker_timer_id
392  );
393  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
394
395  for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
396    rtems_id worker_id;
397
398    sc = rtems_task_create(
399      rtems_build_name('W', 'O', 'R', 'K'),
400      WORKER_PRIORITY,
401      RTEMS_MINIMUM_STACK_SIZE,
402      RTEMS_DEFAULT_MODES,
403      RTEMS_DEFAULT_ATTRIBUTES,
404      &worker_id
405    );
406    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
407
408    sc = rtems_task_start(worker_id, worker_task, worker_index);
409    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
410  }
411
412  run_tests(ctx, 0);
413}
414
415static void Init(rtems_task_argument arg)
416{
417  puts("\n\n*** TEST SMPATOMIC 8 ***");
418
419  test();
420
421  puts("*** END OF TEST SMPATOMIC 8 ***");
422
423  rtems_test_exit(0);
424}
425
426#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
427#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
428
429#define CONFIGURE_SMP_APPLICATION
430
431#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
432
433#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
434
435#define CONFIGURE_MAXIMUM_TIMERS 1
436
437#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
438#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
439#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
440
441#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
442
443#define CONFIGURE_INIT
444
445#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.