[rtems commit] rtems: Add RTEMS_INTERRUPT_REPLACE

Sebastian Huber sebh at rtems.org
Thu Mar 6 08:39:32 UTC 2014


Module:    rtems
Branch:    master
Commit:    718124e4e5bb65edf40584264c972620cf3162d5
Changeset: http://git.rtems.org/rtems/commit/?id=718124e4e5bb65edf40584264c972620cf3162d5

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Mon Mar  3 10:18:01 2014 +0100

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).

---

 c/src/lib/libbsp/shared/src/irq-generic.c |   81 +++++++++++++++++++----------
 cpukit/include/rtems/irq-extension.h      |   35 ++++++++++--
 2 files changed, 83 insertions(+), 33 deletions(-)

diff --git a/c/src/lib/libbsp/shared/src/irq-generic.c b/c/src/lib/libbsp/shared/src/irq-generic.c
index 0343ccb..ad34b4a 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 */
diff --git a/cpukit/include/rtems/irq-extension.h b/cpukit/include/rtems/irq-extension.h
index ff2c6da..35eaf1e 100644
--- a/cpukit/include/rtems/irq-extension.h
+++ b/cpukit/include/rtems/irq-extension.h
@@ -9,12 +9,13 @@
 /*
  * Based on concepts of Pavel Pisa, Till Straumann and Eric Valette.
  *
- * Copyright (c) 2008
- * Embedded Brains GmbH
- * Obere Lagerstr. 30
- * D-82178 Puchheim
- * Germany
- * rtems at embedded-brains.de
+ * Copyright (c) 2008-2014 embedded brains GmbH.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems at embedded-brains.de>
  *
  * The license and distribution terms for this file may be
  * found in the file LICENSE in this distribution or at
@@ -54,6 +55,12 @@ extern "C" {
 #define RTEMS_INTERRUPT_SHARED ((rtems_option) 0x00000000)
 
 /**
+ * @brief Forces that this interrupt handler replaces the first handler with
+ * the same argument.
+ */
+#define RTEMS_INTERRUPT_REPLACE ((rtems_option) 0x00000002)
+
+/**
  * @brief Returns true if the interrupt handler unique option is set.
  */
 #define RTEMS_INTERRUPT_IS_UNIQUE( options) \
@@ -66,6 +73,12 @@ extern "C" {
   (!RTEMS_INTERRUPT_IS_UNIQUE( options))
 
 /**
+ * @brief Returns true if the interrupt handler replace option is set.
+ */
+#define RTEMS_INTERRUPT_IS_REPLACE( options) \
+  ((options) & RTEMS_INTERRUPT_REPLACE)
+
+/**
  * @brief Interrupt handler routine type.
  */
 typedef void (*rtems_interrupt_handler)(void *);
@@ -78,6 +91,7 @@ typedef void (*rtems_interrupt_handler)(void *);
  *
  * - @ref RTEMS_INTERRUPT_UNIQUE
  * - @ref RTEMS_INTERRUPT_SHARED
+ * - @ref RTEMS_INTERRUPT_REPLACE
  *
  * with the @a options parameter for the interrupt handler.
  *
@@ -88,6 +102,13 @@ typedef void (*rtems_interrupt_handler)(void *);
  * If the option @ref RTEMS_INTERRUPT_UNIQUE is set then it shall be ensured
  * that this handler will be the only one for this vector.
  *
+ * If the option @ref RTEMS_INTERRUPT_REPLACE is set then it shall be ensured
+ * that this handler will replace the first handler with the same argument for
+ * this vector if it exists, otherwise an error status shall be returned.  A
+ * second handler with the same argument for this vector shall remain
+ * unchanged.  The new handler will inherit the unique or shared option from
+ * the replaced handler.
+ *
  * You can provide an informative description @a info.  This may be used for
  * system debugging and status tools.  The string has to be persistent during
  * the handler life time.
@@ -108,6 +129,8 @@ typedef void (*rtems_interrupt_handler)(void *);
  * installed and there is already a handler installed this shall be returned.
  * @retval RTEMS_TOO_MANY If a handler with this argument is already installed
  * for the vector this shall be returned.
+ * @retval RTEMS_UNSATISFIED If no handler exists to replace with the specified
+ * argument and vector this shall be returned.
  * @retval RTEMS_IO_ERROR Reserved for board support package specific error
  * conditions.
  */




More information about the vc mailing list