source: rtems/c/src/lib/libbsp/shared/src/irq-server.c @ 5fca9ef

4.115
Last change on this file since 5fca9ef was 5fca9ef, checked in by Sebastian Huber <sebastian.huber@…>, on 03/05/15 at 13:54:09

bsps: Use interrupt lock for interrupt server

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