[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