source: rtems/testsuites/smptests/smplock01/init.c @ d50acdbb

4.11
Last change on this file since d50acdbb was d50acdbb, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 10, 2014 at 7:25:32 AM

score: Add local context to SMP lock API

Add a local context structure to the SMP lock API for acquire and
release pairs. This context can be used to store the ISR level and
profiling information. It may be later used to enable more
sophisticated lock algorithms, e.g. MCS locks.

There is only one lock that cannot be used with a local context. This
is the per-CPU lock since here we would have to transfer the local
context through a context switch which is very complicated.

  • Property mode set to 100644
File size: 7.7 KB
Line 
1/*
2 * Copyright (c) 2013-2014 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/smplock.h>
20#include <rtems/score/smpbarrier.h>
21#include <rtems/score/atomic.h>
22#include <rtems.h>
23
24#include "tmacros.h"
25
26#define TASK_PRIORITY 1
27
28#define CPU_COUNT 32
29
30#define TEST_COUNT 5
31
32typedef enum {
33  INITIAL,
34  START_TEST,
35  STOP_TEST
36} states;
37
38typedef struct {
39  Atomic_Uint state;
40  SMP_barrier_Control barrier;
41  rtems_id timer_id;
42  rtems_interval timeout;
43  unsigned long counter[TEST_COUNT];
44  unsigned long test_counter[TEST_COUNT][CPU_COUNT];
45  SMP_lock_Control lock;
46} global_context;
47
48static global_context context = {
49  .state = ATOMIC_INITIALIZER_UINT(INITIAL),
50  .barrier = SMP_BARRIER_CONTROL_INITIALIZER,
51  .lock = SMP_LOCK_INITIALIZER
52};
53
54static const char *test_names[TEST_COUNT] = {
55  "aquire global lock with local counter",
56  "aquire global lock with global counter",
57  "aquire local lock with local counter",
58  "aquire local lock with global counter",
59  "aquire global lock with busy section"
60};
61
62static void stop_test_timer(rtems_id timer_id, void *arg)
63{
64  global_context *ctx = arg;
65
66  _Atomic_Store_uint(&ctx->state, STOP_TEST, ATOMIC_ORDER_RELEASE);
67}
68
69static void wait_for_state(global_context *ctx, int desired_state)
70{
71  while (
72    _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_ACQUIRE) != desired_state
73  ) {
74    /* Wait */
75  }
76}
77
78static bool assert_state(global_context *ctx, int desired_state)
79{
80  return _Atomic_Load_uint(&ctx->state, ATOMIC_ORDER_RELAXED) == desired_state;
81}
82
83typedef void (*test_body)(
84  int test,
85  global_context *ctx,
86  SMP_barrier_State *bs,
87  unsigned int cpu_count,
88  unsigned int cpu_self
89);
90
91static void test_0_body(
92  int test,
93  global_context *ctx,
94  SMP_barrier_State *bs,
95  unsigned int cpu_count,
96  unsigned int cpu_self
97)
98{
99  unsigned long counter = 0;
100  SMP_lock_Context lock_context;
101
102  while (assert_state(ctx, START_TEST)) {
103    _SMP_lock_Acquire(&ctx->lock, &lock_context);
104    _SMP_lock_Release(&ctx->lock, &lock_context);
105    ++counter;
106  }
107
108  ctx->test_counter[test][cpu_self] = counter;
109}
110
111static void test_1_body(
112  int test,
113  global_context *ctx,
114  SMP_barrier_State *bs,
115  unsigned int cpu_count,
116  unsigned int cpu_self
117)
118{
119  unsigned long counter = 0;
120  SMP_lock_Context lock_context;
121
122  while (assert_state(ctx, START_TEST)) {
123    _SMP_lock_Acquire(&ctx->lock, &lock_context);
124    ++ctx->counter[test];
125    _SMP_lock_Release(&ctx->lock, &lock_context);
126    ++counter;
127  }
128
129  ctx->test_counter[test][cpu_self] = counter;
130}
131
132static void test_2_body(
133  int test,
134  global_context *ctx,
135  SMP_barrier_State *bs,
136  unsigned int cpu_count,
137  unsigned int cpu_self
138)
139{
140  unsigned long counter = 0;
141  SMP_lock_Control lock = SMP_LOCK_INITIALIZER;
142  SMP_lock_Context lock_context;
143
144  while (assert_state(ctx, START_TEST)) {
145    _SMP_lock_Acquire(&lock, &lock_context);
146    _SMP_lock_Release(&lock, &lock_context);
147    ++counter;
148  }
149
150  ctx->test_counter[test][cpu_self] = counter;
151}
152
153static void test_3_body(
154  int test,
155  global_context *ctx,
156  SMP_barrier_State *bs,
157  unsigned int cpu_count,
158  unsigned int cpu_self
159)
160{
161  unsigned long counter = 0;
162  SMP_lock_Control lock = SMP_LOCK_INITIALIZER;
163  SMP_lock_Context lock_context;
164
165  while (assert_state(ctx, START_TEST)) {
166    _SMP_lock_Acquire(&lock, &lock_context);
167
168    /* The counter value is not interesting, only the access to it */
169    ++ctx->counter[test];
170
171    _SMP_lock_Release(&lock, &lock_context);
172    ++counter;
173  }
174
175  ctx->test_counter[test][cpu_self] = counter;
176}
177
178static void busy_section(void)
179{
180  int i;
181
182  for (i = 0; i < 101; ++i) {
183    RTEMS_COMPILER_MEMORY_BARRIER();
184  }
185}
186
187static void test_4_body(
188  int test,
189  global_context *ctx,
190  SMP_barrier_State *bs,
191  unsigned int cpu_count,
192  unsigned int cpu_self
193)
194{
195  unsigned long counter = 0;
196  SMP_lock_Context lock_context;
197
198  while (assert_state(ctx, START_TEST)) {
199    _SMP_lock_Acquire(&ctx->lock, &lock_context);
200    busy_section();
201    _SMP_lock_Release(&ctx->lock, &lock_context);
202    ++counter;
203  }
204
205  ctx->test_counter[test][cpu_self] = counter;
206}
207
208static const test_body test_bodies[TEST_COUNT] = {
209  test_0_body,
210  test_1_body,
211  test_2_body,
212  test_3_body,
213  test_4_body
214};
215
216static void run_tests(
217  global_context *ctx,
218  SMP_barrier_State *bs,
219  unsigned int cpu_count,
220  unsigned int cpu_self,
221  bool master
222)
223{
224  int test;
225
226  for (test = 0; test < TEST_COUNT; ++test) {
227    _SMP_barrier_Wait(&ctx->barrier, bs, cpu_count);
228
229    if (master) {
230      rtems_status_code sc = rtems_timer_fire_after(
231        ctx->timer_id,
232        ctx->timeout,
233        stop_test_timer,
234        ctx
235      );
236      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
237
238      _Atomic_Store_uint(&ctx->state, START_TEST, ATOMIC_ORDER_RELEASE);
239    }
240
241    wait_for_state(ctx, START_TEST);
242
243    (*test_bodies[test])(test, ctx, bs, cpu_count, cpu_self);
244  }
245
246  _SMP_barrier_Wait(&ctx->barrier, bs, cpu_count);
247}
248
249static void task(rtems_task_argument arg)
250{
251  global_context *ctx = (global_context *) arg;
252  uint32_t cpu_count = rtems_smp_get_processor_count();
253  uint32_t cpu_self = rtems_smp_get_current_processor();
254  rtems_status_code sc;
255  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
256
257  run_tests(ctx, &bs, cpu_count, cpu_self, false);
258
259  sc = rtems_task_suspend(RTEMS_SELF);
260  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
261}
262
263static void test(void)
264{
265  global_context *ctx = &context;
266  uint32_t cpu_count = rtems_smp_get_processor_count();
267  uint32_t cpu_self = rtems_smp_get_current_processor();
268  uint32_t cpu;
269  int test;
270  rtems_status_code sc;
271  SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
272
273  for (cpu = 0; cpu < cpu_count; ++cpu) {
274    if (cpu != cpu_self) {
275      rtems_id task_id;
276
277      sc = rtems_task_create(
278        rtems_build_name('T', 'A', 'S', 'K'),
279        TASK_PRIORITY,
280        RTEMS_MINIMUM_STACK_SIZE,
281        RTEMS_DEFAULT_MODES,
282        RTEMS_DEFAULT_ATTRIBUTES,
283        &task_id
284      );
285      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
286
287      sc = rtems_task_start(task_id, task, (rtems_task_argument) ctx);
288      rtems_test_assert(sc == RTEMS_SUCCESSFUL);
289    }
290  }
291
292  ctx->timeout = 10 * rtems_clock_get_ticks_per_second();
293
294  sc = rtems_timer_create(rtems_build_name('T', 'I', 'M', 'R'), &ctx->timer_id);
295  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
296
297  run_tests(ctx, &bs, cpu_count, cpu_self, true);
298
299  for (test = 0; test < TEST_COUNT; ++test) {
300    unsigned long sum = 0;
301
302    printf("%s\n", test_names[test]);
303
304    for (cpu = 0; cpu < cpu_count; ++cpu) {
305      unsigned long local_counter = ctx->test_counter[test][cpu];
306
307      sum += local_counter;
308
309      printf(
310        "\tprocessor %" PRIu32 ", local counter %lu\n",
311        cpu,
312        local_counter
313      );
314    }
315
316    printf(
317      "\tglobal counter %lu, sum of local counter %lu\n",
318      ctx->counter[test],
319      sum
320    );
321  }
322}
323
324static void Init(rtems_task_argument arg)
325{
326  puts("\n\n*** TEST SMPLOCK 1 ***");
327
328  test();
329
330  puts("*** END OF TEST SMPLOCK 1 ***");
331
332  rtems_test_exit(0);
333}
334
335#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
336#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
337
338#define CONFIGURE_SMP_APPLICATION
339
340#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT
341
342#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT
343
344#define CONFIGURE_MAXIMUM_SEMAPHORES 1
345
346#define CONFIGURE_MAXIMUM_TIMERS 1
347
348#define CONFIGURE_INIT_TASK_PRIORITY TASK_PRIORITY
349#define CONFIGURE_INIT_TASK_INITIAL_MODES RTEMS_DEFAULT_MODES
350#define CONFIGURE_INIT_TASK_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
351
352#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
353
354#define CONFIGURE_INIT
355
356#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.