source: rtems/testsuites/smptests/smpatomic08/init.c @ e127c4c

4.11
Last change on this file since e127c4c was e127c4c, checked in by Sebastian Huber <sebastian.huber@…>, on Aug 29, 2013 at 8:03:38 AM

smptests/smpatomic08: Fix race conditions

  • Property mode set to 100644
File size: 7.5 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_Uint value;
28        Atomic_Uint sense;
29} SMP_barrier_Control;
30
31typedef struct {
32        uint_fast32_t sense;
33} SMP_barrier_State;
34
35#define SMP_BARRIER_CONTROL_INITIALIZER \
36  { ATOMIC_INITIALIZER_UINT( 0 ), ATOMIC_INITIALIZER_UINT( 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  uint_fast32_t count
44)
45{
46  uint_fast32_t sense = ~state->sense;
47  uint_fast32_t previous_value;
48
49  state->sense = sense;
50
51  previous_value = _Atomic_Fetch_add_uint(
52    &control->value,
53    1,
54    ATOMIC_ORDER_RELAXED
55  );
56
57  if ( previous_value + 1 == count ) {
58    _Atomic_Store_uint( &control->value, 0, ATOMIC_ORDER_RELAXED );
59    _Atomic_Store_uint( &control->sense, sense, ATOMIC_ORDER_RELEASE );
60  } else {
61    while (
62      _Atomic_Load_uint( &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_Uint stop;
77  SMP_barrier_Control barrier;
78  size_t worker_count;
79  rtems_id stop_worker_timer_id;
80  Atomic_Uint global_uint;
81  uint_fast32_t per_worker_uint[CPU_COUNT];
82  uint32_t flag_counter;
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_UINT(0),
94  .barrier = SMP_BARRIER_CONTROL_INITIALIZER
95};
96
97static bool stop(test_context *ctx)
98{
99  return _Atomic_Load_uint(&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_atomic_add_init(test_context *ctx)
108{
109  _Atomic_Init_uint(&ctx->global_uint, 0);
110}
111
112static void test_atomic_add_body(test_context *ctx, size_t worker_index)
113{
114  uint_fast32_t counter = 0;
115
116  while (!stop(ctx)) {
117    ++counter;
118    _Atomic_Fetch_add_uint(&ctx->global_uint, 1, ATOMIC_ORDER_RELAXED);
119  }
120
121  ctx->per_worker_uint[worker_index] = counter;
122}
123
124static void test_atomic_add_fini(test_context *ctx)
125{
126  uint_fast32_t expected_counter = 0;
127  uint_fast32_t actual_counter;
128  size_t worker_index;
129
130  printf("=== atomic add test case ==\n");
131
132  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
133    uint_fast32_t worker_counter = ctx->per_worker_uint[worker_index];
134
135    expected_counter += worker_counter;
136
137    printf(
138      "atomic add worker %zu counter: %" PRIuFAST32 "\n",
139      worker_index,
140      worker_counter
141    );
142  }
143
144  actual_counter = _Atomic_Load_uint(&ctx->global_uint, ATOMIC_ORDER_RELAXED);
145
146  printf(
147    "global counter: expected = %" PRIuFAST32 ", actual = %" PRIuFAST32 "\n",
148    expected_counter,
149    actual_counter
150  );
151
152  rtems_test_assert(expected_counter == actual_counter);
153}
154
155static void test_atomic_flag_init(test_context *ctx)
156{
157  _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
158  ctx->flag_counter = 0;
159}
160
161static void test_atomic_flag_body(test_context *ctx, size_t worker_index)
162{
163  uint_fast32_t counter = 0;
164
165  while (!stop(ctx)) {
166    while (_Atomic_Flag_test_and_set(&ctx->global_flag, ATOMIC_ORDER_ACQUIRE)) {
167      /* Wait */
168    }
169
170    ++counter;
171    ++ctx->flag_counter;
172
173    _Atomic_Flag_clear(&ctx->global_flag, ATOMIC_ORDER_RELEASE);
174  }
175
176  ctx->per_worker_uint[worker_index] = counter;
177}
178
179static void test_atomic_flag_fini(test_context *ctx)
180{
181  uint_fast32_t expected_counter = 0;
182  uint_fast32_t actual_counter;
183  size_t worker_index;
184
185  printf("=== atomic flag test case ===\n");
186
187  for (worker_index = 0; worker_index < ctx->worker_count; ++worker_index) {
188    uint_fast32_t worker_counter = ctx->per_worker_uint[worker_index];
189
190    expected_counter += worker_counter;
191
192    printf(
193      "atomic flag worker %zu counter: %" PRIuFAST32 "\n",
194      worker_index,
195      worker_counter
196    );
197  }
198
199  actual_counter = ctx->flag_counter;
200
201  printf(
202    "global flag counter: expected = %" PRIuFAST32 ", actual = %" PRIuFAST32 "\n",
203    expected_counter,
204    actual_counter
205  );
206
207  rtems_test_assert(expected_counter == actual_counter);
208}
209
210static const test_case test_cases[] = {
211  { test_atomic_add_init, test_atomic_add_body, test_atomic_add_fini },
212  { test_atomic_flag_init, test_atomic_flag_body, test_atomic_flag_fini }
213};
214
215#define TEST_COUNT RTEMS_ARRAY_SIZE(test_cases)
216
217static void stop_worker_timer(rtems_id timer_id, void *arg)
218{
219  test_context *ctx = arg;
220
221  _Atomic_Store_uint(&ctx->stop, 1, ATOMIC_ORDER_RELAXED);
222}
223
224static void start_worker_stop_timer(test_context *ctx)
225{
226  rtems_status_code sc;
227
228  _Atomic_Store_uint(&ctx->stop, 0, ATOMIC_ORDER_RELEASE);
229
230  sc = rtems_timer_fire_after(
231    ctx->stop_worker_timer_id,
232    rtems_clock_get_ticks_per_second(),
233    stop_worker_timer,
234    ctx
235  );
236  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
237}
238
239static void run_tests(test_context *ctx, size_t worker_index)
240{
241  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
242  size_t test;
243
244  for (test = 0; test < TEST_COUNT; ++test) {
245    const test_case *tc = &test_cases[test];
246
247    if (is_master_worker(worker_index)) {
248      start_worker_stop_timer(ctx);
249      (*tc->init)(ctx);
250    }
251
252    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
253
254    (*tc->body)(ctx, worker_index);
255
256    _SMP_barrier_Wait(&ctx->barrier, &bs, ctx->worker_count);
257
258    if (is_master_worker(worker_index)) {
259      (*tc->fini)(ctx);
260    }
261  }
262}
263
264static void worker_task(size_t worker_index)
265{
266  test_context *ctx = &test_instance;
267
268  run_tests(ctx, worker_index);
269
270  (void) rtems_task_suspend(RTEMS_SELF);
271  rtems_test_assert(0);
272}
273
274static void test(void)
275{
276  test_context *ctx = &test_instance;
277  rtems_status_code sc;
278  size_t worker_index;
279
280  ctx->worker_count = rtems_smp_get_processor_count();
281
282  sc = rtems_timer_create(
283    rtems_build_name('S', 'T', 'O', 'P'),
284    &ctx->stop_worker_timer_id
285  );
286  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
287
288  for (worker_index = 1; worker_index < ctx->worker_count; ++worker_index) {
289    rtems_id worker_id;
290
291    sc = rtems_task_create(
292      rtems_build_name('W', 'O', 'R', 'K'),
293      WORKER_PRIORITY,
294      RTEMS_MINIMUM_STACK_SIZE,
295      RTEMS_DEFAULT_MODES,
296      RTEMS_DEFAULT_ATTRIBUTES,
297      &worker_id
298    );
299    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
300
301    sc = rtems_task_start(worker_id, worker_task, worker_index);
302    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
303  }
304
305  run_tests(ctx, 0);
306}
307
308static void Init(rtems_task_argument arg)
309{
310  puts("\n\n*** TEST SMPATOMIC 8 ***");
311
312  test();
313
314  puts("*** END OF TEST SMPATOMIC 8 ***");
315
316  rtems_test_exit(0);
317}
318
319#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
320#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
321
322#define CONFIGURE_SMP_APPLICATION
323
324#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
325
326#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
327
328#define CONFIGURE_MAXIMUM_TIMERS 1
329
330#define CONFIGURE_INIT_TASK_PRIORITY MASTER_PRIORITY
331#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
332#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
333
334#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
335
336#define CONFIGURE_INIT
337
338#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.