source: rtems/testsuites/sptests/spintrcritical23/init.c @ 6a941e3

4.115
Last change on this file since 6a941e3 was 6a941e3, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 17, 2015 at 3:24:44 PM

score: Fix _Thread_Change_priority()

Atomically update the current priority of a thread and the wait queue.
Serialize the scheduler update in a separate critical section with a
generation number.

New test sptests/spintrcritical23.

Close #2310.

  • Property mode set to 100644
File size: 4.4 KB
Line 
1/*
2 * Copyright (c) 2015 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 <tmacros.h>
20#include <intrcritical.h>
21
22#include <string.h>
23
24#include <rtems.h>
25#include <rtems/score/schedulerpriority.h>
26#include <rtems/score/threadimpl.h>
27
28const char rtems_test_name[] = "SPINTRCRITICAL 23";
29
30typedef struct {
31  RTEMS_INTERRUPT_LOCK_MEMBER(lock)
32  rtems_id task_id;
33  Thread_Control *tcb;
34  rtems_task_priority priority_task;
35  rtems_task_priority priority_interrupt;
36  uint32_t priority_generation;
37  Scheduler_priority_Node scheduler_node;
38  bool done;
39} test_context;
40
41static test_context ctx_instance;
42
43static Thread_Control *get_tcb(rtems_id id)
44{
45  Objects_Locations location;
46  Thread_Control *tcb;
47
48  tcb = _Thread_Get(id, &location);
49  _Objects_Put(&tcb->Object);
50
51  rtems_test_assert(tcb != NULL && location == OBJECTS_LOCAL);
52
53  return tcb;
54}
55
56static bool scheduler_node_unchanged(const test_context *ctx)
57{
58   return memcmp(
59     &ctx->scheduler_node,
60     ctx->tcb->Scheduler.node,
61     sizeof(ctx->scheduler_node)
62   ) == 0;
63}
64
65static void change_priority(rtems_id timer, void *arg)
66{
67  /* The arg is NULL */
68  test_context *ctx = &ctx_instance;
69  rtems_interrupt_lock_context lock_context;
70  rtems_task_priority priority_interrupt;
71  rtems_task_priority priority_task;
72
73  rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
74  if (
75    ctx->priority_generation != ctx->tcb->priority_generation
76      && scheduler_node_unchanged(ctx)
77  ) {
78    ctx->done = true;
79    priority_interrupt = ctx->priority_interrupt;
80    priority_task = ctx->priority_task;
81  }
82  rtems_interrupt_lock_release(&ctx->lock, &lock_context);
83
84  if (ctx->done) {
85    rtems_status_code sc;
86    rtems_task_priority previous;
87
88    sc = rtems_task_set_priority(
89      ctx->task_id,
90      priority_interrupt,
91      &previous
92    );
93    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
94    rtems_test_assert(previous == priority_task);
95  }
96}
97
98static bool test_body(void *arg)
99{
100  test_context *ctx = arg;
101  rtems_status_code sc;
102  rtems_interrupt_lock_context lock_context;
103  rtems_task_priority priority_last;
104  rtems_task_priority priority_task;
105  rtems_task_priority priority_interrupt;
106  rtems_task_priority previous;
107
108  rtems_interrupt_lock_acquire(&ctx->lock, &lock_context);
109  priority_last = ctx->priority_task;
110  priority_task = 1 + (priority_last + 1) % 3;
111  priority_interrupt = 1 + (priority_task + 1) % 3;
112  ctx->priority_task = priority_task;
113  ctx->priority_interrupt = priority_interrupt;
114  ctx->priority_generation = ctx->tcb->priority_generation;
115  memcpy(
116    &ctx->scheduler_node,
117    ctx->tcb->Scheduler.node,
118    sizeof(ctx->scheduler_node)
119  );
120  rtems_interrupt_lock_release(&ctx->lock, &lock_context);
121
122  sc = rtems_task_set_priority(
123    ctx->task_id,
124    priority_task,
125    &previous
126  );
127  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
128  rtems_test_assert(previous == priority_last);
129
130  if (ctx->done) {
131    sc = rtems_task_set_priority(
132      ctx->task_id,
133      RTEMS_CURRENT_PRIORITY,
134      &previous
135    );
136    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
137    rtems_test_assert(previous == priority_interrupt);
138  }
139
140  return ctx->done;
141}
142
143static void Init(rtems_task_argument arg)
144{
145  test_context *ctx = &ctx_instance;
146  rtems_status_code sc;
147
148  TEST_BEGIN();
149
150  rtems_interrupt_lock_initialize(&ctx->lock, "Test");
151  ctx->priority_task = 1;
152
153  sc = rtems_task_create(
154    rtems_build_name('T', 'E', 'S', 'T'),
155    ctx->priority_task,
156    RTEMS_MINIMUM_STACK_SIZE,
157    RTEMS_DEFAULT_MODES,
158    RTEMS_DEFAULT_ATTRIBUTES,
159    &ctx->task_id
160  );
161  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
162
163  ctx->tcb = get_tcb(ctx->task_id);
164
165  interrupt_critical_section_test(test_body, ctx, change_priority);
166  rtems_test_assert(ctx->done);
167
168  TEST_END();
169  rtems_test_exit(0);
170}
171
172#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
173#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
174
175#define CONFIGURE_MICROSECONDS_PER_TICK 1000
176
177#define CONFIGURE_MAXIMUM_TASKS 2
178#define CONFIGURE_MAXIMUM_TIMERS 1
179#define CONFIGURE_MAXIMUM_USER_EXTENSIONS 1
180
181#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
182
183#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
184
185#define CONFIGURE_INIT
186
187#include <rtems/confdefs.h>
Note: See TracBrowser for help on using the repository browser.