summaryrefslogtreecommitdiffstats
path: root/c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-03 10:18:01 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2014-03-06 09:43:59 +0100
commit718124e4e5bb65edf40584264c972620cf3162d5 (patch)
tree2da00c66efb43a4f8841ad16a7e304b09dd23c87 /c
parentbsps: SMP support for generic interrupt support (diff)
downloadrtems-718124e4e5bb65edf40584264c972620cf3162d5.tar.bz2
rtems: Add RTEMS_INTERRUPT_REPLACE
A new option RTEMS_INTERRUPT_REPLACE is introduced that permits updating the first interrupt handler for the registered interrupt vector and matching argument. If no match is found, the install function fails with RTEMS_UNSATISFIED. The Interrupt Manager Extension offers interrupt handlers with an argument pointer. It is impossible to update two words (handler and argument) atomically on most architectures. In order to avoid an SMP lock in bsp_interrupt_handler_dispatch() which would degrade the interrupt response time an alternative must be provided that makes it possible to tear-down interrupt sources without an SMP lock. Add RTEMS_INTERRUPT_REPLACE option to Interrupt Manager Extension. This enables a clean tear-down of interrupt sources on SMP configurations. Instead of an interrupt handler removal a replacement handler can be installed to silence an interrupt source. This can be used in contexts that allow no sophisticated synchronization (e.g. in atexit() or fatal handlers).
Diffstat (limited to 'c')
-rw-r--r--c/src/lib/libbsp/shared/src/irq-generic.c81
1 files changed, 54 insertions, 27 deletions
diff --git a/c/src/lib/libbsp/shared/src/irq-generic.c b/c/src/lib/libbsp/shared/src/irq-generic.c
index 0343ccb6cf..ad34b4a4be 100644
--- a/c/src/lib/libbsp/shared/src/irq-generic.c
+++ b/c/src/lib/libbsp/shared/src/irq-generic.c
@@ -211,10 +211,8 @@ static rtems_status_code bsp_interrupt_handler_install(
rtems_interrupt_level level;
rtems_vector_number index = 0;
bsp_interrupt_handler_entry *head = NULL;
- bsp_interrupt_handler_entry *tail = NULL;
- bsp_interrupt_handler_entry *current = NULL;
- bsp_interrupt_handler_entry *match = NULL;
bool enable_vector = false;
+ bool replace = RTEMS_INTERRUPT_IS_REPLACE(options);
/* Check parameters and system state */
if (!bsp_interrupt_is_initialized()) {
@@ -237,6 +235,12 @@ static rtems_status_code bsp_interrupt_handler_install(
head = &bsp_interrupt_handler_table [index];
if (bsp_interrupt_is_empty_handler_entry(head)) {
+ if (replace) {
+ /* No handler to replace exists */
+ bsp_interrupt_unlock();
+ return RTEMS_UNSATISFIED;
+ }
+
/*
* No real handler installed yet. So allocate a new index in
* the handler table and fill the entry with life.
@@ -260,10 +264,15 @@ static rtems_status_code bsp_interrupt_handler_install(
/* This is the first handler so enable the vector later */
enable_vector = true;
} else {
+ bsp_interrupt_handler_entry *current = head;
+ bsp_interrupt_handler_entry *tail = NULL;
+ bsp_interrupt_handler_entry *match = NULL;
+
/* Ensure that a unique handler remains unique */
if (
- RTEMS_INTERRUPT_IS_UNIQUE(options)
- || bsp_interrupt_is_handler_unique(index)
+ !replace
+ && (RTEMS_INTERRUPT_IS_UNIQUE(options)
+ || bsp_interrupt_is_handler_unique(index))
) {
/*
* Tried to install a unique handler on a not empty
@@ -277,41 +286,59 @@ static rtems_status_code bsp_interrupt_handler_install(
* Search for the list tail and check if the handler is already
* installed.
*/
- current = head;
do {
- if (current->handler == handler && current->arg == arg) {
+ if (
+ match == NULL
+ && (current->handler == handler || replace)
+ && current->arg == arg
+ ) {
match = current;
}
tail = current;
current = current->next;
} while (current != NULL);
- /* Ensure the handler is not already installed */
- if (match != NULL) {
- /* The handler is already installed */
- bsp_interrupt_unlock();
- return RTEMS_TOO_MANY;
- }
+ if (replace) {
+ /* Ensure that a handler to replace exists */
+ if (match == NULL) {
+ bsp_interrupt_unlock();
+ return RTEMS_UNSATISFIED;
+ }
- /* Allocate a new entry */
- current = bsp_interrupt_allocate_handler_entry();
- if (current == NULL) {
- /* Not enough memory */
- bsp_interrupt_unlock();
- return RTEMS_NO_MEMORY;
+ /* Use existing entry */
+ current = match;
+ } else {
+ /* Ensure the handler is not already installed */
+ if (match != NULL) {
+ /* The handler is already installed */
+ bsp_interrupt_unlock();
+ return RTEMS_TOO_MANY;
+ }
+
+ /* Allocate a new entry */
+ current = bsp_interrupt_allocate_handler_entry();
+ if (current == NULL) {
+ /* Not enough memory */
+ bsp_interrupt_unlock();
+ return RTEMS_NO_MEMORY;
+ }
}
- /* Set entry */
+ /* Update existing entry or set new entry */
current->handler = handler;
- current->arg = arg;
current->info = info;
- current->next = NULL;
- /* Link to list tail */
- bsp_interrupt_disable(level);
- bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
- tail->next = current;
- bsp_interrupt_enable(level);
+ if (!replace) {
+ /* Set new entry */
+ current->arg = arg;
+ current->next = NULL;
+
+ /* Link to list tail */
+ bsp_interrupt_disable(level);
+ bsp_interrupt_fence(ATOMIC_ORDER_RELEASE);
+ tail->next = current;
+ bsp_interrupt_enable(level);
+ }
}
/* Make the handler unique if necessary */