source: rtems/c/src/lib/libbsp/shared/src/irq-server.c @ 610909f

5
Last change on this file since 610909f was 610909f, checked in by Sebastian Huber <sebastian.huber@…>, on 11/11/15 at 11:05:22

irq-server: Fix race condition on SMP systems

  • Property mode set to 100644
File size: 6.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_interrupt
5 *
6 * @brief Generic BSP interrupt server implementation.
7 */
8
9/*
10 * Copyright (c) 2009, 2015 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <stdlib.h>
24
25#include <rtems.h>
26#include <rtems/chain.h>
27
28#include <bsp/irq-generic.h>
29
30RTEMS_INTERRUPT_LOCK_DEFINE(
31  static,
32  bsp_interrupt_server_lock,
33  "Interrupt Server"
34)
35
36typedef struct bsp_interrupt_server_entry {
37  rtems_chain_node node;
38  rtems_vector_number vector;
39  rtems_interrupt_handler handler;
40  void *arg;
41} bsp_interrupt_server_entry;
42
43static rtems_id bsp_interrupt_server_id = RTEMS_ID_NONE;
44
45static RTEMS_CHAIN_DEFINE_EMPTY(bsp_interrupt_server_chain);
46
47static rtems_status_code bsp_interrupt_server_is_initialized(void)
48{
49  if (bsp_interrupt_server_id != RTEMS_ID_NONE) {
50    return RTEMS_SUCCESSFUL;
51  } else {
52    return RTEMS_INCORRECT_STATE;
53  }
54}
55
56static unsigned bsp_interrupt_server_errors;
57
58static void bsp_interrupt_server_trigger(void *arg)
59{
60  rtems_interrupt_lock_context lock_context;
61  bsp_interrupt_server_entry *e = arg;
62
63  bsp_interrupt_vector_disable(e->vector);
64
65  rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
66
67  if (rtems_chain_is_node_off_chain(&e->node)) {
68    rtems_chain_append_unprotected(&bsp_interrupt_server_chain, &e->node);
69  } else {
70    ++bsp_interrupt_server_errors;
71  }
72
73  rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
74
75  rtems_event_system_send(bsp_interrupt_server_id, RTEMS_EVENT_SYSTEM_SERVER);
76}
77
78static bsp_interrupt_server_entry *bsp_interrupt_server_get_entry(void)
79{
80  rtems_interrupt_lock_context lock_context;
81  bsp_interrupt_server_entry *e;
82  rtems_chain_control *chain;
83
84  rtems_interrupt_lock_acquire(&bsp_interrupt_server_lock, &lock_context);
85  chain = &bsp_interrupt_server_chain;
86
87  if (!rtems_chain_is_empty(chain)) {
88    e = (bsp_interrupt_server_entry *)
89      rtems_chain_get_first_unprotected(chain);
90    rtems_chain_set_off_chain(&e->node);
91  } else {
92    e = NULL;
93  }
94
95  rtems_interrupt_lock_release(&bsp_interrupt_server_lock, &lock_context);
96
97  return e;
98}
99
100static void bsp_interrupt_server_task(rtems_task_argument arg)
101{
102  rtems_status_code sc = RTEMS_SUCCESSFUL;
103
104  while (true) {
105    rtems_event_set events = 0;
106    bsp_interrupt_server_entry *e = NULL;
107
108    sc = rtems_event_system_receive(
109      RTEMS_EVENT_SYSTEM_SERVER,
110      RTEMS_EVENT_ALL | RTEMS_WAIT,
111      RTEMS_NO_TIMEOUT,
112      &events
113    );
114    if (sc != RTEMS_SUCCESSFUL) {
115      break;
116    }
117
118    while ((e = bsp_interrupt_server_get_entry()) != NULL) {
119      (*e->handler)(e->arg);
120
121      bsp_interrupt_vector_enable(e->vector);
122    }
123  }
124
125  rtems_task_delete(RTEMS_SELF);
126}
127
128typedef struct {
129  rtems_interrupt_handler handler;
130  void *arg;
131  bsp_interrupt_server_entry *entry;
132} bsp_interrupt_server_iterate_entry;
133
134static void bsp_interrupt_server_per_handler_routine(
135  void *iterate_arg,
136  const char *info,
137  rtems_option options,
138  rtems_interrupt_handler handler,
139  void *handler_arg
140)
141{
142  bsp_interrupt_server_iterate_entry *ie = iterate_arg;
143  bsp_interrupt_server_entry *e = handler_arg;
144
145  if (handler == bsp_interrupt_server_trigger) {
146    if (e->handler == ie->handler && e->arg == ie->arg) {
147      ie->entry = e;
148    }
149  }
150}
151
152rtems_status_code rtems_interrupt_server_handler_install(
153  rtems_id server,
154  rtems_vector_number vector,
155  const char *info,
156  rtems_option options,
157  rtems_interrupt_handler handler,
158  void *arg
159)
160{
161  rtems_status_code sc = RTEMS_SUCCESSFUL;
162  bsp_interrupt_server_entry *e = NULL;
163
164  sc = bsp_interrupt_server_is_initialized();
165  if (sc != RTEMS_SUCCESSFUL) {
166    return sc;
167  }
168
169  if (server != RTEMS_ID_NONE) {
170    return RTEMS_NOT_IMPLEMENTED;
171  }
172
173  if (RTEMS_INTERRUPT_IS_SHARED(options)) {
174    return RTEMS_NOT_IMPLEMENTED;
175  }
176
177  e = calloc(1, sizeof(*e));
178  if (e == NULL) {
179    return RTEMS_NO_MEMORY;
180  }
181
182  e->vector = vector;
183  e->handler = handler;
184  e->arg = arg;
185
186  sc = rtems_interrupt_handler_install(
187    vector,
188    info,
189    options,
190    bsp_interrupt_server_trigger,
191    e
192  );
193  if (sc != RTEMS_SUCCESSFUL) {
194    free(e);
195
196    return sc;
197  }
198
199  return RTEMS_SUCCESSFUL;
200}
201
202rtems_status_code rtems_interrupt_server_handler_remove(
203  rtems_id server,
204  rtems_vector_number vector,
205  rtems_interrupt_handler handler,
206  void *arg
207)
208{
209  rtems_status_code sc = RTEMS_SUCCESSFUL;
210  bsp_interrupt_server_iterate_entry ie = {
211    .handler = handler,
212    .arg = arg,
213    .entry = NULL
214  };
215
216  sc = bsp_interrupt_server_is_initialized();
217  if (sc != RTEMS_SUCCESSFUL) {
218    return sc;
219  }
220
221  if (server != RTEMS_ID_NONE) {
222    return RTEMS_NOT_IMPLEMENTED;
223  }
224
225  /* Query corresponding interrupt server entry */
226  sc = rtems_interrupt_handler_iterate(
227    vector,
228    bsp_interrupt_server_per_handler_routine,
229    &ie
230  );
231  if (sc != RTEMS_SUCCESSFUL) {
232    return sc;
233  } else if (ie.entry == NULL) {
234    return RTEMS_INVALID_ID;
235  }
236
237  sc = rtems_interrupt_handler_remove(
238    vector,
239    bsp_interrupt_server_trigger,
240    ie.entry
241  );
242  if (sc != RTEMS_SUCCESSFUL) {
243    return sc;
244  }
245
246  free(ie.entry);
247
248  return RTEMS_SUCCESSFUL;
249}
250
251rtems_status_code rtems_interrupt_server_initialize(
252  rtems_task_priority priority,
253  size_t stack_size,
254  rtems_mode modes,
255  rtems_attribute attributes,
256  rtems_id *server
257)
258{
259  rtems_status_code sc = RTEMS_SUCCESSFUL;
260
261  if (server != NULL) {
262    return RTEMS_NOT_IMPLEMENTED;
263  }
264
265  sc = rtems_task_create(
266    rtems_build_name('I', 'R', 'Q', 'S'),
267    priority,
268    stack_size,
269    modes,
270    attributes,
271    &bsp_interrupt_server_id
272  );
273  if (sc != RTEMS_SUCCESSFUL) {
274    return RTEMS_TOO_MANY;
275  }
276
277  sc = rtems_task_start(
278    bsp_interrupt_server_id,
279    bsp_interrupt_server_task,
280    0
281  );
282  if (sc != RTEMS_SUCCESSFUL) {
283    /* In this case we could also panic */
284    rtems_task_delete(bsp_interrupt_server_id);
285    bsp_interrupt_server_id = RTEMS_ID_NONE;
286
287    return RTEMS_TOO_MANY;
288  }
289
290  return RTEMS_SUCCESSFUL;
291}
Note: See TracBrowser for help on using the repository browser.