rtems: Add rtems_interrupt_local_disable|enable()

Add rtems_interrupt_local_disable|enable() as suggested by Pavel Pisa to
emphasize that interrupts are only disabled on the current processor.
Do not define the rtems_interrupt_disable|enable|flash() macros and
functions on SMP configurations since they don't ensure system wide
mutual exclusion.
This commit is contained in:
Sebastian Huber
2015-06-19 14:57:44 +02:00
parent f9090ac82d
commit cdf30f0550
10 changed files with 241 additions and 84 deletions

View File

@@ -72,7 +72,7 @@ void boot_card(
* Make sure interrupts are disabled. * Make sure interrupts are disabled.
*/ */
(void) bsp_isr_level; (void) bsp_isr_level;
rtems_interrupt_disable( bsp_isr_level ); rtems_interrupt_local_disable( bsp_isr_level );
bsp_boot_cmdline = cmdline; bsp_boot_cmdline = cmdline;

View File

@@ -89,10 +89,15 @@ rtems_status_code rtems_interrupt_catch(
); );
#endif #endif
#if !defined(RTEMS_SMP)
/** /**
* @brief Disable RTEMS Interrupt * @brief Disable RTEMS Interrupt
* *
* @note The interrupt level shall be of type @ref rtems_interrupt_level. * @note The interrupt level shall be of type @ref rtems_interrupt_level.
*
* This macro is only available on uni-processor configurations. The macro
* rtems_interrupt_local_disable() is available on all configurations.
*/ */
#define rtems_interrupt_disable( _isr_cookie ) \ #define rtems_interrupt_disable( _isr_cookie ) \
_ISR_Disable(_isr_cookie) _ISR_Disable(_isr_cookie)
@@ -101,6 +106,9 @@ rtems_status_code rtems_interrupt_catch(
* @brief Enable RTEMS Interrupt * @brief Enable RTEMS Interrupt
* *
* @note The interrupt level shall be of type @ref rtems_interrupt_level. * @note The interrupt level shall be of type @ref rtems_interrupt_level.
*
* This macro is only available on uni-processor configurations. The macro
* rtems_interrupt_local_enable() is available on all configurations.
*/ */
#define rtems_interrupt_enable( _isr_cookie ) \ #define rtems_interrupt_enable( _isr_cookie ) \
_ISR_Enable(_isr_cookie) _ISR_Enable(_isr_cookie)
@@ -109,10 +117,40 @@ rtems_status_code rtems_interrupt_catch(
* @brief Flash RTEMS Interrupt * @brief Flash RTEMS Interrupt
* *
* @note The interrupt level shall be of type @ref rtems_interrupt_level. * @note The interrupt level shall be of type @ref rtems_interrupt_level.
*
* This macro is only available on uni-processor configurations. The macro
* rtems_interrupt_local_disable() and rtems_interrupt_local_enable() is
* available on all configurations.
*/ */
#define rtems_interrupt_flash( _isr_cookie ) \ #define rtems_interrupt_flash( _isr_cookie ) \
_ISR_Flash(_isr_cookie) _ISR_Flash(_isr_cookie)
#endif /* RTEMS_SMP */
/**
* @brief This macro disables the interrupts on the current processor.
*
* On SMP configurations this will not ensure system wide mutual exclusion.
* Use interrupt locks instead.
*
* @param[in] _isr_cookie The previous interrupt level is returned. The type
* of this variable must be rtems_interrupt_level.
*
* @see rtems_interrupt_local_enable().
*/
#define rtems_interrupt_local_disable( _isr_cookie ) \
_ISR_Disable_without_giant( _isr_cookie )
/**
* @brief This macro restores the previous interrupt level on the current
* processor.
*
* @param[in] _isr_cookie The previous interrupt level returned by
* rtems_interrupt_local_disable().
*/
#define rtems_interrupt_local_enable( _isr_cookie ) \
_ISR_Enable_without_giant( _isr_cookie )
/** /**
* @brief RTEMS Interrupt Is in Progress * @brief RTEMS Interrupt Is in Progress
* *

View File

@@ -23,6 +23,8 @@
#include <rtems/score/isr.h> #include <rtems/score/isr.h>
#include <rtems/rtems/intr.h> #include <rtems/rtems/intr.h>
#if !defined(RTEMS_SMP)
/* /*
* Undefine all of these is normally a macro and we want a real body in * Undefine all of these is normally a macro and we want a real body in
* the library for other language bindings. * the library for other language bindings.
@@ -30,7 +32,6 @@
#undef rtems_interrupt_disable #undef rtems_interrupt_disable
#undef rtems_interrupt_enable #undef rtems_interrupt_enable
#undef rtems_interrupt_flash #undef rtems_interrupt_flash
#undef rtems_interrupt_is_in_progress
/* /*
* Prototype them to avoid warnings * Prototype them to avoid warnings
@@ -38,7 +39,6 @@
rtems_interrupt_level rtems_interrupt_disable( void ); rtems_interrupt_level rtems_interrupt_disable( void );
void rtems_interrupt_enable( rtems_interrupt_level previous_level ); void rtems_interrupt_enable( rtems_interrupt_level previous_level );
void rtems_interrupt_flash( rtems_interrupt_level previous_level ); void rtems_interrupt_flash( rtems_interrupt_level previous_level );
bool rtems_interrupt_is_in_progress( void );
/* /*
* Now define real bodies * Now define real bodies
@@ -66,6 +66,11 @@ void rtems_interrupt_flash(
_ISR_Flash( previous_level ); _ISR_Flash( previous_level );
} }
#endif /* RTEMS_SMP */
#undef rtems_interrupt_is_in_progress
bool rtems_interrupt_is_in_progress( void );
bool rtems_interrupt_is_in_progress( void ) bool rtems_interrupt_is_in_progress( void )
{ {
return _ISR_Is_in_progress(); return _ISR_Is_in_progress();

View File

@@ -21,6 +21,8 @@ directive:
@item @code{@value{DIRPREFIX}interrupt_disable} - Disable Interrupts @item @code{@value{DIRPREFIX}interrupt_disable} - Disable Interrupts
@item @code{@value{DIRPREFIX}interrupt_enable} - Enable Interrupts @item @code{@value{DIRPREFIX}interrupt_enable} - Enable Interrupts
@item @code{@value{DIRPREFIX}interrupt_flash} - Flash Interrupt @item @code{@value{DIRPREFIX}interrupt_flash} - Flash Interrupt
@item @code{@value{DIRPREFIX}interrupt_local_disable} - Disable Interrupts on Current Processor
@item @code{@value{DIRPREFIX}interrupt_local_enable} - Enable Interrupts on Current Processor
@item @code{@value{DIRPREFIX}interrupt_lock_initialize} - Initialize an ISR Lock @item @code{@value{DIRPREFIX}interrupt_lock_initialize} - Initialize an ISR Lock
@item @code{@value{DIRPREFIX}interrupt_lock_acquire} - Acquire an ISR Lock @item @code{@value{DIRPREFIX}interrupt_lock_acquire} - Acquire an ISR Lock
@item @code{@value{DIRPREFIX}interrupt_lock_release} - Release an ISR Lock @item @code{@value{DIRPREFIX}interrupt_lock_release} - Release an ISR Lock
@@ -397,6 +399,10 @@ This directive will not cause the calling task to be preempted.
parameter.} parameter.}
@end ifset @end ifset
This directive is only available on uni-processor configurations. The
directive @code{@value{DIRPREFIX}interrupt_local_disable} is available on all
configurations.
@c @c
@c @c
@c @c
@@ -441,6 +447,9 @@ and will be enabled when this directive returns to the caller.
This directive will not cause the calling task to be preempted. This directive will not cause the calling task to be preempted.
This directive is only available on uni-processor configurations. The
directive @code{@value{DIRPREFIX}interrupt_local_enable} is available on all
configurations.
@c @c
@c @c
@@ -486,6 +495,91 @@ and will be redisabled when this directive returns to the caller.
This directive will not cause the calling task to be preempted. This directive will not cause the calling task to be preempted.
This directive is only available on uni-processor configurations. The
directives @code{@value{DIRPREFIX}interrupt_local_disable} and
@code{@value{DIRPREFIX}interrupt_local_enable} is available on all
configurations.
@c
@c
@c
@page
@subsection INTERRUPT_LOCAL_DISABLE - Disable Interrupts on Current Processor
@cindex disable interrupts
@subheading CALLING SEQUENCE:
@ifset is-C
@findex rtems_interrupt_local_disable
@example
void rtems_interrupt_local_disable(
rtems_interrupt_level level
);
/* this is implemented as a macro and sets level as a side-effect */
@end example
@end ifset
@subheading DIRECTIVE STATUS CODES:
NONE
@subheading DESCRIPTION:
This directive disables all maskable interrupts and returns
the previous @code{level}. A later invocation of the
@code{@value{DIRPREFIX}interrupt_local_enable} directive should be used to
restore the interrupt level.
@subheading NOTES:
This directive will not cause the calling task to be preempted.
@ifset is-C
@b{This directive is implemented as a macro which modifies the @code{level}
parameter.}
@end ifset
On SMP configurations this will not ensure system wide mutual exclusion. Use
interrupt locks instead.
@c
@c
@c
@page
@subsection INTERRUPT_LOCAL_ENABLE - Enable Interrupts on Current Processor
@cindex enable interrupts
@subheading CALLING SEQUENCE:
@ifset is-C
@findex rtems_interrupt_local_enable
@example
void rtems_interrupt_local_enable(
rtems_interrupt_level level
);
@end example
@end ifset
@subheading DIRECTIVE STATUS CODES:
NONE
@subheading DESCRIPTION:
This directive enables maskable interrupts to the @code{level}
which was returned by a previous call to
@code{@value{DIRPREFIX}interrupt_local_disable}.
Immediately prior to invoking this directive, maskable interrupts should
be disabled by a call to @code{@value{DIRPREFIX}interrupt_local_disable}
and will be enabled when this directive returns to the caller.
@subheading NOTES:
This directive will not cause the calling task to be preempted.
@c @c
@c @c
@c @c

View File

@@ -94,12 +94,12 @@ static void test_system_not_up(void)
puts( "start with a system state != SYSTEM_STATE_UP" ); puts( "start with a system state != SYSTEM_STATE_UP" );
rtems_interrupt_disable( level ); rtems_interrupt_local_disable( level );
System_state_Codes state = _System_state_Get(); System_state_Codes state = _System_state_Get();
_System_state_Set( SYSTEM_STATE_TERMINATED ); _System_state_Set( SYSTEM_STATE_TERMINATED );
test_call_heap_walk( true ); test_call_heap_walk( true );
_System_state_Set( state ); _System_state_Set( state );
rtems_interrupt_enable( level ); rtems_interrupt_local_enable( level );
} }
static void test_check_control(void) static void test_check_control(void)

View File

@@ -18,8 +18,11 @@ endif
if NETTESTS if NETTESTS
## loopback tests a network loopback interface ## loopback tests a network loopback interface
_SUBDIRS += loopback _SUBDIRS += loopback
if HAS_SMP
else
_SUBDIRS += pppd _SUBDIRS += pppd
endif endif
endif
include $(top_srcdir)/../automake/test-subdirs.am include $(top_srcdir)/../automake/test-subdirs.am
include $(top_srcdir)/../automake/local.am include $(top_srcdir)/../automake/local.am

View File

@@ -26,6 +26,7 @@ RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
RTEMS_CHECK_CPUOPTS([RTEMS_MULTIPROCESSING]) RTEMS_CHECK_CPUOPTS([RTEMS_MULTIPROCESSING])
RTEMS_CHECK_CXX(RTEMS_BSP) RTEMS_CHECK_CXX(RTEMS_BSP)
RTEMS_CHECK_CPUOPTS([RTEMS_NETWORKING]) RTEMS_CHECK_CPUOPTS([RTEMS_NETWORKING])
RTEMS_CHECK_CPUOPTS([RTEMS_SMP])
CXXTESTS=$HAS_CPLUSPLUS CXXTESTS=$HAS_CPLUSPLUS
AS_IF([test $HAS_CPLUSPLUS = yes],[ AS_IF([test $HAS_CPLUSPLUS = yes],[
@@ -52,6 +53,7 @@ AS_IF([test $HAS_CPLUSPLUS = yes],[
AM_CONDITIONAL([CXXTESTS],[test $CXXTESTS = "yes"]) AM_CONDITIONAL([CXXTESTS],[test $CXXTESTS = "yes"])
AM_CONDITIONAL(NETTESTS,test "$rtems_cv_RTEMS_NETWORKING" = "yes") AM_CONDITIONAL(NETTESTS,test "$rtems_cv_RTEMS_NETWORKING" = "yes")
AM_CONDITIONAL(MPTESTS,test "$rtems_cv_RTEMS_MULTIPROCESSING" = "yes") AM_CONDITIONAL(MPTESTS,test "$rtems_cv_RTEMS_MULTIPROCESSING" = "yes")
AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes")
# FIXME: We should get rid of this. It's a cludge. # FIXME: We should get rid of this. It's a cludge.
AC_CHECK_SIZEOF([time_t]) AC_CHECK_SIZEOF([time_t])

View File

@@ -243,8 +243,7 @@ static void test_clock_tick_functions( void )
rtems_interrupt_level level; rtems_interrupt_level level;
Watchdog_Interval saved_ticks; Watchdog_Interval saved_ticks;
_Thread_Disable_dispatch(); rtems_interrupt_local_disable( level );
rtems_interrupt_disable( level );
saved_ticks = _Watchdog_Ticks_since_boot; saved_ticks = _Watchdog_Ticks_since_boot;
@@ -287,16 +286,19 @@ static void test_clock_tick_functions( void )
_Watchdog_Ticks_since_boot = saved_ticks; _Watchdog_Ticks_since_boot = saved_ticks;
rtems_interrupt_enable( level ); rtems_interrupt_local_enable( level );
_Thread_Enable_dispatch();
} }
void test_interrupt_inline(void) void test_interrupt_inline(void)
{ {
rtems_interrupt_level level; rtems_interrupt_level level;
rtems_interrupt_level level_1;
rtems_mode level_mode_body; rtems_mode level_mode_body;
rtems_mode level_mode_macro; rtems_mode level_mode_macro;
bool in_isr; bool in_isr;
uint32_t isr_level_0;
uint32_t isr_level_1;
uint32_t isr_level_2;
puts( "interrupt is in progress (use body)" ); puts( "interrupt is in progress (use body)" );
in_isr = rtems_interrupt_is_in_progress(); in_isr = rtems_interrupt_is_in_progress();
@@ -305,20 +307,33 @@ void test_interrupt_inline(void)
rtems_test_exit( 0 ); rtems_test_exit( 0 );
} }
#if !defined(RTEMS_SMP)
puts( "interrupt disable (use inline)" ); puts( "interrupt disable (use inline)" );
_Thread_Disable_dispatch();
rtems_interrupt_disable( level ); rtems_interrupt_disable( level );
_Thread_Enable_dispatch();
puts( "interrupt flash (use inline)" ); puts( "interrupt flash (use inline)" );
_Thread_Disable_dispatch();
rtems_interrupt_flash( level ); rtems_interrupt_flash( level );
_Thread_Enable_dispatch();
puts( "interrupt enable (use inline)" ); puts( "interrupt enable (use inline)" );
_Thread_Disable_dispatch();
rtems_interrupt_enable( level ); rtems_interrupt_enable( level );
_Thread_Enable_dispatch(); #endif /* RTEMS_SMP */
isr_level_0 = _ISR_Get_level();
rtems_test_assert( isr_level_0 == 0 );
rtems_interrupt_local_disable( level );
isr_level_1 = _ISR_Get_level();
rtems_test_assert( isr_level_1 != isr_level_0 );
rtems_interrupt_local_disable( level_1 );
isr_level_2 = _ISR_Get_level();
rtems_test_assert( isr_level_2 == isr_level_1 );
rtems_interrupt_local_enable( level_1 );
rtems_test_assert( _ISR_Get_level() == isr_level_1 );
rtems_interrupt_local_enable( level );
rtems_test_assert( _ISR_Get_level() == isr_level_0 );
puts( "interrupt level mode (use inline)" ); puts( "interrupt level mode (use inline)" );
level_mode_body = rtems_interrupt_level_body( level ); level_mode_body = rtems_interrupt_level_body( level );
@@ -329,6 +344,7 @@ void test_interrupt_inline(void)
} }
volatile int isr_in_progress_body; volatile int isr_in_progress_body;
volatile int isr_in_progress_inline; volatile int isr_in_progress_inline;
void check_isr_in_progress_inline(void) void check_isr_in_progress_inline(void)
@@ -336,25 +352,6 @@ void check_isr_in_progress_inline(void)
isr_in_progress_inline = rtems_interrupt_is_in_progress() ? 1 : 2; isr_in_progress_inline = rtems_interrupt_is_in_progress() ? 1 : 2;
} }
#undef rtems_interrupt_disable
extern rtems_interrupt_level rtems_interrupt_disable(void);
#undef rtems_interrupt_enable
extern void rtems_interrupt_enable(rtems_interrupt_level previous_level);
#undef rtems_interrupt_flash
extern void rtems_interrupt_flash(rtems_interrupt_level previous_level);
#undef rtems_interrupt_is_in_progress
extern bool rtems_interrupt_is_in_progress(void);
rtems_timer_service_routine test_isr_in_progress(
rtems_id timer,
void *arg
)
{
check_isr_in_progress_inline();
isr_in_progress_body = rtems_interrupt_is_in_progress() ? 1 : 2;
}
void check_isr_worked( void check_isr_worked(
char *s, char *s,
int result int result
@@ -429,16 +426,70 @@ rtems_timer_service_routine test_unblock_task(
directive_failed( status, "rtems_task_resume" ); directive_failed( status, "rtems_task_resume" );
} }
#undef rtems_interrupt_disable
extern rtems_interrupt_level rtems_interrupt_disable(void);
#undef rtems_interrupt_enable
extern void rtems_interrupt_enable(rtems_interrupt_level previous_level);
#undef rtems_interrupt_flash
extern void rtems_interrupt_flash(rtems_interrupt_level previous_level);
#undef rtems_interrupt_is_in_progress
extern bool rtems_interrupt_is_in_progress(void);
static void test_interrupt_body(void)
{
#if !defined(RTEMS_SMP)
rtems_interrupt_level level;
rtems_mode level_mode_body;
rtems_mode level_mode_macro;
bool in_isr;
puts( "interrupt disable (use body)" );
level = rtems_interrupt_disable();
puts( "interrupt disable (use body)" );
level = rtems_interrupt_disable();
puts( "interrupt flash (use body)" );
rtems_interrupt_flash( level );
puts( "interrupt enable (use body)" );
rtems_interrupt_enable( level );
puts( "interrupt level mode (use body)" );
level_mode_body = rtems_interrupt_level_body( level );
level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
if ( level_mode_macro == level_mode_body ) {
puts("test seems to work");
}
/*
* Test interrupt bodies
*/
puts( "interrupt is in progress (use body)" );
in_isr = rtems_interrupt_is_in_progress();
if ( in_isr ) {
puts( "interrupt reported to be is in progress (body)" );
rtems_test_exit( 0 );
}
#endif /* RTEMS_SMP */
}
rtems_timer_service_routine test_isr_in_progress(
rtems_id timer,
void *arg
)
{
check_isr_in_progress_inline();
isr_in_progress_body = rtems_interrupt_is_in_progress() ? 1 : 2;
}
rtems_task Init( rtems_task Init(
rtems_task_argument argument rtems_task_argument argument
) )
{ {
rtems_time_of_day time; rtems_time_of_day time;
rtems_status_code status; rtems_status_code status;
rtems_interrupt_level level;
rtems_mode level_mode_body;
rtems_mode level_mode_macro;
bool in_isr;
rtems_id timer; rtems_id timer;
int i; int i;
@@ -523,47 +574,8 @@ rtems_task Init(
break; break;
} }
/*
* Test interrupt inline versions
*/
test_interrupt_inline(); test_interrupt_inline();
test_interrupt_body();
/*
* Test interrupt bodies
*/
puts( "interrupt is in progress (use body)" );
in_isr = rtems_interrupt_is_in_progress();
if ( in_isr ) {
puts( "interrupt reported to be is in progress (body)" );
rtems_test_exit( 0 );
}
puts( "interrupt disable (use body)" );
_Thread_Disable_dispatch();
level = rtems_interrupt_disable();
_Thread_Enable_dispatch();
puts( "interrupt disable (use body)" );
_Thread_Disable_dispatch();
level = rtems_interrupt_disable();
_Thread_Enable_dispatch();
puts( "interrupt flash (use body)" );
_Thread_Disable_dispatch();
rtems_interrupt_flash( level );
_Thread_Enable_dispatch();
puts( "interrupt enable (use body)" );
_Thread_Disable_dispatch();
rtems_interrupt_enable( level );
_Thread_Enable_dispatch();
puts( "interrupt level mode (use body)" );
level_mode_body = rtems_interrupt_level_body( level );
level_mode_macro = RTEMS_INTERRUPT_LEVEL(level);
if ( level_mode_macro == level_mode_body ) {
puts("test seems to work");
}
/* /*
* Test ISR in progress from actual ISR * Test ISR in progress from actual ISR

View File

@@ -42,16 +42,14 @@ static rtems_driver_address_table test_driver = {
#define test_interrupt_context_enter( level ) \ #define test_interrupt_context_enter( level ) \
do { \ do { \
_Thread_Disable_dispatch(); \ rtems_interrupt_local_disable( level ); \
rtems_interrupt_disable( level ); \
++_ISR_Nest_level; \ ++_ISR_Nest_level; \
} while (0) } while (0)
#define test_interrupt_context_leave( level ) \ #define test_interrupt_context_leave( level ) \
do { \ do { \
--_ISR_Nest_level; \ --_ISR_Nest_level; \
rtems_interrupt_enable( level ); \ rtems_interrupt_local_enable( level ); \
_Thread_Enable_dispatch(); \
} while (0) } while (0)
rtems_task Init( rtems_task Init(

View File

@@ -341,15 +341,20 @@ rtems_task High_task(
_Thread_Disable_dispatch(); _Thread_Disable_dispatch();
benchmark_timer_initialize(); benchmark_timer_initialize();
rtems_interrupt_disable( level ); rtems_interrupt_local_disable( level );
isr_disable_time = benchmark_timer_read(); isr_disable_time = benchmark_timer_read();
benchmark_timer_initialize(); benchmark_timer_initialize();
#if defined(RTEMS_SMP)
rtems_interrupt_local_enable( level );
rtems_interrupt_local_disable( level );
#else
rtems_interrupt_flash( level ); rtems_interrupt_flash( level );
#endif
isr_flash_time = benchmark_timer_read(); isr_flash_time = benchmark_timer_read();
benchmark_timer_initialize(); benchmark_timer_initialize();
rtems_interrupt_enable( level ); rtems_interrupt_local_enable( level );
isr_enable_time = benchmark_timer_read(); isr_enable_time = benchmark_timer_read();
_Thread_Enable_dispatch(); _Thread_Enable_dispatch();