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 + * <rt...@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 +@code{@value{DIRPREFIX}interrupt_enable} or +@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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel