[PATCH] rtems: rtems_interrupt_enable/flash/disable()

Sebastian Huber sebastian.huber at embedded-brains.de
Fri Jun 12 08:31:54 UTC 2015


Use a global ticket lock on SMP configurations to ensure mutual
exclusion across the system.
---
 c/src/lib/libbsp/shared/bootcard.c      |  7 ++--
 cpukit/rtems/Makefile.am                |  1 +
 cpukit/rtems/include/rtems/rtems/intr.h | 48 +++++++++++++++++++++--
 cpukit/rtems/src/intrbody.c             | 13 +++++++
 cpukit/rtems/src/intrthebighammer.c     | 67 +++++++++++++++++++++++++++++++++
 doc/user/intr.t                         |  7 +++-
 testsuites/sptests/sp37/init.c          |  6 ---
 7 files changed, 136 insertions(+), 13 deletions(-)
 create mode 100644 cpukit/rtems/src/intrthebighammer.c

diff --git a/c/src/lib/libbsp/shared/bootcard.c b/c/src/lib/libbsp/shared/bootcard.c
index 4f91aa9..2a17c94 100644
--- a/c/src/lib/libbsp/shared/bootcard.c
+++ b/c/src/lib/libbsp/shared/bootcard.c
@@ -66,13 +66,14 @@ void boot_card(
   const char *cmdline
 )
 {
-  rtems_interrupt_level  bsp_isr_level;
+  ISR_Level bsp_isr_level;
 
   /*
-   *  Make sure interrupts are disabled.
+   * Make sure interrupts are disabled.  Do not use rtems_interrupt_disable()
+   * here, since on SMP configurations this is not a simple interrupt disable.
    */
+  _ISR_Disable_without_giant( bsp_isr_level );
   (void) bsp_isr_level;
-  rtems_interrupt_disable( bsp_isr_level );
 
   bsp_boot_cmdline = cmdline;
 
diff --git a/cpukit/rtems/Makefile.am b/cpukit/rtems/Makefile.am
index f38990d..00bf53a 100644
--- a/cpukit/rtems/Makefile.am
+++ b/cpukit/rtems/Makefile.am
@@ -136,6 +136,7 @@ librtems_a_SOURCES += src/ratemondata.c
 ## INTR_C_FILES
 librtems_a_SOURCES += src/intrbody.c
 librtems_a_SOURCES += src/intrcatch.c
+librtems_a_SOURCES += src/intrthebighammer.c
 
 ## BARRIER_C_FILES
 librtems_a_SOURCES += src/barrier.c
diff --git a/cpukit/rtems/include/rtems/rtems/intr.h b/cpukit/rtems/include/rtems/rtems/intr.h
index 259120f..0ad002b 100644
--- a/cpukit/rtems/include/rtems/rtems/intr.h
+++ b/cpukit/rtems/include/rtems/rtems/intr.h
@@ -89,29 +89,71 @@ rtems_status_code rtems_interrupt_catch(
 );
 #endif
 
+#if defined(RTEMS_SMP)
+/*
+ * On SMP configurations replace the simple interrupt disable/enable with
+ * global recursive lock, also known as The Big Hammer.
+ */
+
+typedef struct {
+  SMP_ticket_lock_Control Lock;
+  SMP_lock_Stats_context Stats;
+  Thread_Control *owner;
+  uint32_t nest_level;
+} The_big_hammer_Control;
+
+extern The_big_hammer_Control _The_big_hammer;
+
+rtems_interrupt_level _The_big_hammer_Acquire( void );
+
+void _The_big_hammer_Release( rtems_interrupt_level level );
+#endif
+
 /**
  *  @brief Disable RTEMS Interrupt
  *
  *  @note The interrupt level shall be of type @ref rtems_interrupt_level.
  */
+#if defined(RTEMS_SMP)
+#define rtems_interrupt_disable( _isr_cookie ) \
+  do { \
+    _isr_cookie = _The_big_hammer_Acquire(); \
+  } while ( 0 )
+#else
 #define rtems_interrupt_disable( _isr_cookie ) \
-    _ISR_Disable(_isr_cookie)
+  _ISR_Disable( _isr_cookie )
+#endif
 
 /**
  *  @brief Enable RTEMS Interrupt
  *
  *  @note The interrupt level shall be of type @ref rtems_interrupt_level.
  */
+#if defined(RTEMS_SMP)
+#define rtems_interrupt_enable( _isr_cookie ) \
+  do { \
+    _The_big_hammer_Release( _isr_cookie ); \
+  } while ( 0 )
+#else
 #define rtems_interrupt_enable( _isr_cookie ) \
-    _ISR_Enable(_isr_cookie)
+  _ISR_Enable( _isr_cookie )
+#endif
 
 /**
  *  @brief Flash RTEMS Interrupt
  *
  *  @note The interrupt level shall be of type @ref rtems_interrupt_level.
  */
+#if defined(RTEMS_SMP)
+#define rtems_interrupt_flash( _isr_cookie ) \
+  do { \
+    rtems_interrupt_enable( _isr_cookie ); \
+    rtems_interrupt_disable( _isr_cookie ); \
+  } while ( 0 )
+#else
 #define rtems_interrupt_flash( _isr_cookie ) \
-    _ISR_Flash(_isr_cookie)
+  _ISR_Flash( _isr_cookie )
+#endif
 
 /**
  *  @brief RTEMS Interrupt Is in Progress
diff --git a/cpukit/rtems/src/intrbody.c b/cpukit/rtems/src/intrbody.c
index 6b37eb2..9638d6c 100644
--- a/cpukit/rtems/src/intrbody.c
+++ b/cpukit/rtems/src/intrbody.c
@@ -47,7 +47,11 @@ rtems_interrupt_level rtems_interrupt_disable( void )
 {
   rtems_interrupt_level previous_level;
 
+#if defined(RTEMS_SMP)
+  previous_level = _The_big_hammer_Acquire();
+#else
   _ISR_Disable( previous_level );
+#endif
 
   return previous_level;
 }
@@ -56,14 +60,23 @@ void rtems_interrupt_enable(
   rtems_interrupt_level previous_level
 )
 {
+#if defined(RTEMS_SMP)
+  _The_big_hammer_Release( previous_level );
+#else
   _ISR_Enable( previous_level );
+#endif
 }
 
 void rtems_interrupt_flash(
   rtems_interrupt_level previous_level
 )
 {
+#if defined(RTEMS_SMP)
+  _The_big_hammer_Release( previous_level );
+  _The_big_hammer_Acquire();
+#else
   _ISR_Flash( previous_level );
+#endif
 }
 
 bool rtems_interrupt_is_in_progress( void )
diff --git a/cpukit/rtems/src/intrthebighammer.c b/cpukit/rtems/src/intrthebighammer.c
new file mode 100644
index 0000000..37d8e88
--- /dev/null
+++ b/cpukit/rtems/src/intrthebighammer.c
@@ -0,0 +1,67 @@
+/**
+ * @file
+ *
+ * @ingroup ClassicINTR
+ *
+ * @brief The Big Hammer
+ */
+
+/*
+ * Copyright (c) 2015 embedded brains GmbH.  All rights reserved.
+ *
+ *  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
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#if HAVE_CONFIG_H
+  #include "config.h"
+#endif
+
+#include <rtems/rtems/intr.h>
+
+#if defined(RTEMS_SMP)
+The_big_hammer_Control _The_big_hammer = {
+  .Lock = SMP_TICKET_LOCK_INITIALIZER( "The Big Hammer" )
+};
+
+rtems_interrupt_level _The_big_hammer_Acquire( void )
+{
+  The_big_hammer_Control *hammer = &_The_big_hammer;
+  Thread_Control         *executing;
+  rtems_interrupt_level   previous_level;
+
+  _ISR_Disable_without_giant( previous_level );
+
+  executing = _Thread_Executing;
+
+  if ( hammer->owner != executing ) {
+    _SMP_ticket_lock_Acquire( &hammer->Lock, &hammer->Stats );
+    hammer->owner = executing;
+    hammer->nest_level = 1;
+  } else {
+    ++hammer->nest_level;
+  }
+
+  return previous_level;
+}
+
+void _The_big_hammer_Release( rtems_interrupt_level previous_level )
+{
+  The_big_hammer_Control *hammer = &_The_big_hammer;
+
+  --hammer->nest_level;
+  if ( hammer->nest_level == 0 ) {
+    hammer->owner = NULL;
+    _SMP_ticket_lock_Release( &hammer->Lock, &hammer->Stats );
+  }
+
+  _ISR_Enable_without_giant( previous_level );
+}
+#endif
diff --git a/doc/user/intr.t b/doc/user/intr.t
index 6cb6a26..05049a7 100644
--- a/doc/user/intr.t
+++ b/doc/user/intr.t
@@ -386,7 +386,12 @@ NONE
 This directive disables all maskable interrupts and returns
 the previous @code{level}.  A later invocation of the
 @code{@value{DIRPREFIX}interrupt_enable} directive should be used to
-restore the interrupt level.
+restore the interrupt level.  On SMP configurations a global recursive lock is
+acquired after the interrupt disable to ensure mutual exclusion across the
+system.  This lock is released in the corresponding
+ at code{@value{DIRPREFIX}interrupt_enable} or
+ at code{@value{DIRPREFIX}interrupt_flash}.  The owner of the lock is the
+executing task.
 
 @subheading NOTES:
 
diff --git a/testsuites/sptests/sp37/init.c b/testsuites/sptests/sp37/init.c
index 647485e..77beb28 100644
--- a/testsuites/sptests/sp37/init.c
+++ b/testsuites/sptests/sp37/init.c
@@ -306,19 +306,13 @@ void test_interrupt_inline(void)
   }
 
   puts( "interrupt disable (use inline)" );
-  _Thread_Disable_dispatch();
   rtems_interrupt_disable( level );
-  _Thread_Enable_dispatch();
 
   puts( "interrupt flash (use inline)" );
-  _Thread_Disable_dispatch();
   rtems_interrupt_flash( level );
-  _Thread_Enable_dispatch();
 
   puts( "interrupt enable (use inline)" );
-  _Thread_Disable_dispatch();
   rtems_interrupt_enable( level );
-  _Thread_Enable_dispatch();
 
   puts( "interrupt level mode (use inline)" );
   level_mode_body = rtems_interrupt_level_body( level );
-- 
1.8.4.5



More information about the devel mailing list