From cdf30f0550432648ac005e3f71814b7f708a4ce3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 19 Jun 2015 14:57:44 +0200 Subject: 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. --- c/src/lib/libbsp/shared/bootcard.c | 2 +- cpukit/rtems/include/rtems/rtems/intr.h | 38 ++++++++ cpukit/rtems/src/intrbody.c | 9 +- doc/user/intr.t | 94 +++++++++++++++++++ testsuites/libtests/heapwalk/init.c | 4 +- testsuites/samples/Makefile.am | 3 + testsuites/samples/configure.ac | 2 + testsuites/sptests/sp37/init.c | 158 +++++++++++++++++--------------- testsuites/sptests/sp40/init.c | 6 +- testsuites/tmtests/tm26/task1.c | 9 +- 10 files changed, 241 insertions(+), 84 deletions(-) diff --git a/c/src/lib/libbsp/shared/bootcard.c b/c/src/lib/libbsp/shared/bootcard.c index 4f91aa9c4e..0ee5e12cd0 100644 --- a/c/src/lib/libbsp/shared/bootcard.c +++ b/c/src/lib/libbsp/shared/bootcard.c @@ -72,7 +72,7 @@ void boot_card( * Make sure interrupts are disabled. */ (void) bsp_isr_level; - rtems_interrupt_disable( bsp_isr_level ); + rtems_interrupt_local_disable( bsp_isr_level ); bsp_boot_cmdline = cmdline; diff --git a/cpukit/rtems/include/rtems/rtems/intr.h b/cpukit/rtems/include/rtems/rtems/intr.h index 259120fdc2..d084959fa9 100644 --- a/cpukit/rtems/include/rtems/rtems/intr.h +++ b/cpukit/rtems/include/rtems/rtems/intr.h @@ -89,10 +89,15 @@ rtems_status_code rtems_interrupt_catch( ); #endif +#if !defined(RTEMS_SMP) + /** * @brief Disable RTEMS Interrupt * * @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 ) \ _ISR_Disable(_isr_cookie) @@ -101,6 +106,9 @@ rtems_status_code rtems_interrupt_catch( * @brief Enable RTEMS Interrupt * * @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 ) \ _ISR_Enable(_isr_cookie) @@ -109,10 +117,40 @@ rtems_status_code rtems_interrupt_catch( * @brief Flash RTEMS Interrupt * * @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 ) \ _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 * diff --git a/cpukit/rtems/src/intrbody.c b/cpukit/rtems/src/intrbody.c index 6b37eb26ca..a82dc101e6 100644 --- a/cpukit/rtems/src/intrbody.c +++ b/cpukit/rtems/src/intrbody.c @@ -23,6 +23,8 @@ #include #include +#if !defined(RTEMS_SMP) + /* * Undefine all of these is normally a macro and we want a real body in * the library for other language bindings. @@ -30,7 +32,6 @@ #undef rtems_interrupt_disable #undef rtems_interrupt_enable #undef rtems_interrupt_flash -#undef rtems_interrupt_is_in_progress /* * Prototype them to avoid warnings @@ -38,7 +39,6 @@ rtems_interrupt_level rtems_interrupt_disable( void ); void rtems_interrupt_enable( 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 @@ -66,6 +66,11 @@ void rtems_interrupt_flash( _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 ) { return _ISR_Is_in_progress(); diff --git a/doc/user/intr.t b/doc/user/intr.t index 6cb6a266c6..cf106f39d2 100644 --- a/doc/user/intr.t +++ b/doc/user/intr.t @@ -21,6 +21,8 @@ directive: @item @code{@value{DIRPREFIX}interrupt_disable} - Disable Interrupts @item @code{@value{DIRPREFIX}interrupt_enable} - Enable Interrupts @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_acquire} - Acquire 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.} @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 @@ -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 is only available on uni-processor configurations. The +directive @code{@value{DIRPREFIX}interrupt_local_enable} is available on all +configurations. @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 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 diff --git a/testsuites/libtests/heapwalk/init.c b/testsuites/libtests/heapwalk/init.c index 80073e8f50..3bd6c91ce4 100644 --- a/testsuites/libtests/heapwalk/init.c +++ b/testsuites/libtests/heapwalk/init.c @@ -94,12 +94,12 @@ static void test_system_not_up(void) 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_Set( SYSTEM_STATE_TERMINATED ); test_call_heap_walk( true ); _System_state_Set( state ); - rtems_interrupt_enable( level ); + rtems_interrupt_local_enable( level ); } static void test_check_control(void) diff --git a/testsuites/samples/Makefile.am b/testsuites/samples/Makefile.am index 08455d3742..374617b7e4 100644 --- a/testsuites/samples/Makefile.am +++ b/testsuites/samples/Makefile.am @@ -18,8 +18,11 @@ endif if NETTESTS ## loopback tests a network loopback interface _SUBDIRS += loopback +if HAS_SMP +else _SUBDIRS += pppd endif +endif include $(top_srcdir)/../automake/test-subdirs.am include $(top_srcdir)/../automake/local.am diff --git a/testsuites/samples/configure.ac b/testsuites/samples/configure.ac index e6f12d032f..91a36612df 100644 --- a/testsuites/samples/configure.ac +++ b/testsuites/samples/configure.ac @@ -26,6 +26,7 @@ RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP) RTEMS_CHECK_CPUOPTS([RTEMS_MULTIPROCESSING]) RTEMS_CHECK_CXX(RTEMS_BSP) RTEMS_CHECK_CPUOPTS([RTEMS_NETWORKING]) +RTEMS_CHECK_CPUOPTS([RTEMS_SMP]) CXXTESTS=$HAS_CPLUSPLUS AS_IF([test $HAS_CPLUSPLUS = yes],[ @@ -52,6 +53,7 @@ AS_IF([test $HAS_CPLUSPLUS = yes],[ AM_CONDITIONAL([CXXTESTS],[test $CXXTESTS = "yes"]) AM_CONDITIONAL(NETTESTS,test "$rtems_cv_RTEMS_NETWORKING" = "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. AC_CHECK_SIZEOF([time_t]) diff --git a/testsuites/sptests/sp37/init.c b/testsuites/sptests/sp37/init.c index 0846491700..1dd434f52c 100644 --- a/testsuites/sptests/sp37/init.c +++ b/testsuites/sptests/sp37/init.c @@ -243,8 +243,7 @@ static void test_clock_tick_functions( void ) rtems_interrupt_level level; Watchdog_Interval saved_ticks; - _Thread_Disable_dispatch(); - rtems_interrupt_disable( level ); + rtems_interrupt_local_disable( level ); saved_ticks = _Watchdog_Ticks_since_boot; @@ -287,16 +286,19 @@ static void test_clock_tick_functions( void ) _Watchdog_Ticks_since_boot = saved_ticks; - rtems_interrupt_enable( level ); - _Thread_Enable_dispatch(); + rtems_interrupt_local_enable( level ); } void test_interrupt_inline(void) { rtems_interrupt_level level; + rtems_interrupt_level level_1; rtems_mode level_mode_body; rtems_mode level_mode_macro; 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)" ); in_isr = rtems_interrupt_is_in_progress(); @@ -305,20 +307,33 @@ void test_interrupt_inline(void) rtems_test_exit( 0 ); } +#if !defined(RTEMS_SMP) 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(); +#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)" ); 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_inline; 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; } -#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( char *s, int result @@ -429,16 +426,70 @@ rtems_timer_service_routine test_unblock_task( 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_argument argument ) { rtems_time_of_day time; rtems_status_code status; - rtems_interrupt_level level; - rtems_mode level_mode_body; - rtems_mode level_mode_macro; - bool in_isr; rtems_id timer; int i; @@ -523,47 +574,8 @@ rtems_task Init( break; } - /* - * Test interrupt inline versions - */ test_interrupt_inline(); - - /* - * 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_interrupt_body(); /* * Test ISR in progress from actual ISR diff --git a/testsuites/sptests/sp40/init.c b/testsuites/sptests/sp40/init.c index 5b0ad7d98c..d3b547bbbe 100644 --- a/testsuites/sptests/sp40/init.c +++ b/testsuites/sptests/sp40/init.c @@ -42,16 +42,14 @@ static rtems_driver_address_table test_driver = { #define test_interrupt_context_enter( level ) \ do { \ - _Thread_Disable_dispatch(); \ - rtems_interrupt_disable( level ); \ + rtems_interrupt_local_disable( level ); \ ++_ISR_Nest_level; \ } while (0) #define test_interrupt_context_leave( level ) \ do { \ --_ISR_Nest_level; \ - rtems_interrupt_enable( level ); \ - _Thread_Enable_dispatch(); \ + rtems_interrupt_local_enable( level ); \ } while (0) rtems_task Init( diff --git a/testsuites/tmtests/tm26/task1.c b/testsuites/tmtests/tm26/task1.c index ee662184c5..5b19c3d3b6 100644 --- a/testsuites/tmtests/tm26/task1.c +++ b/testsuites/tmtests/tm26/task1.c @@ -341,15 +341,20 @@ rtems_task High_task( _Thread_Disable_dispatch(); benchmark_timer_initialize(); - rtems_interrupt_disable( level ); + rtems_interrupt_local_disable( level ); isr_disable_time = benchmark_timer_read(); benchmark_timer_initialize(); +#if defined(RTEMS_SMP) + rtems_interrupt_local_enable( level ); + rtems_interrupt_local_disable( level ); +#else rtems_interrupt_flash( level ); +#endif isr_flash_time = benchmark_timer_read(); benchmark_timer_initialize(); - rtems_interrupt_enable( level ); + rtems_interrupt_local_enable( level ); isr_enable_time = benchmark_timer_read(); _Thread_Enable_dispatch(); -- cgit v1.2.3