From c7bc6d44cbd563c72afb7e9355c7350c16acb27b Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 10 Jun 2013 11:14:35 +0200 Subject: rtems: Add interrupt locks Interrupt locks are low-level lock to protect critical sections accessed by threads and interrupt service routines. --- cpukit/rtems/include/rtems/rtems/intr.h | 135 +++++++++++++++++++++++++ doc/user/intr.t | 170 ++++++++++++++++++++++++++++++++ testsuites/sptests/sp37/init.c | 17 ++++ 3 files changed, 322 insertions(+) diff --git a/cpukit/rtems/include/rtems/rtems/intr.h b/cpukit/rtems/include/rtems/rtems/intr.h index ea6dc6b64a..d687e462e3 100644 --- a/cpukit/rtems/include/rtems/rtems/intr.h +++ b/cpukit/rtems/include/rtems/rtems/intr.h @@ -26,6 +26,7 @@ extern "C" { #endif #include +#include /** * @defgroup ClassicINTR Interrupts @@ -134,6 +135,140 @@ rtems_status_code rtems_interrupt_catch( */ #define rtems_interrupt_clear( _interrupt_to_clear ) +/** + * @defgroup ClassicINTRLocks Interrupt Locks + * + * @ingroup ClassicINTR + * + * @brief Low-level lock to protect critical sections accessed by threads and + * interrupt service routines. + * + * This synchronization primitive is supported on SMP configurations. + * + * @{ + */ + +/** + * @brief Interrupt lock control. + */ +typedef struct { + #if defined( RTEMS_SMP ) + SMP_lock_Control lock; + #endif +} rtems_interrupt_lock; + +/** + * @brief Initializer for static initialization of interrupt locks. + */ +#if defined( RTEMS_SMP ) + #define RTEMS_INTERRUPT_LOCK_INITIALIZER \ + { SMP_LOCK_INITIALIZER } +#else + #define RTEMS_INTERRUPT_LOCK_INITIALIZER \ + { } +#endif + +/** + * @brief Initializes an interrupt lock. + * + * Concurrent initialization leads to unpredictable results. + */ +#if defined( RTEMS_SMP ) + #define rtems_interrupt_lock_initialize( _lock ) \ + _SMP_lock_Initialize( &( _lock )->lock ) +#else + #define rtems_interrupt_lock_initialize( _lock ) \ + do { \ + (void) _lock; \ + } while (0) +#endif + +/** + * @brief Acquires an interrupt lock. + * + * Interrupts will be disabled. On SMP configurations this function acquires a + * SMP lock. + * + * This function can be used in thread and interrupt context. + * + * @see rtems_interrupt_lock_release(). + */ +#if defined( RTEMS_SMP ) + #define rtems_interrupt_lock_acquire( _lock, _isr_cookie ) \ + _SMP_lock_ISR_disable_and_acquire( &( _lock )->lock, _isr_cookie ) +#else + #define rtems_interrupt_lock_acquire( _lock, _isr_cookie ) \ + do { \ + (void) _lock; \ + rtems_interrupt_disable( _isr_cookie ); \ + } while (0) +#endif + +/** + * @brief Releases an interrupt lock. + * + * The interrupt status will be restored. On SMP configurations this function + * releases a SMP lock. + * + * This function can be used in thread and interrupt context. + * + * @see rtems_interrupt_lock_acquire(). + */ +#if defined( RTEMS_SMP ) + #define rtems_interrupt_lock_release( _lock, _isr_cookie ) \ + _SMP_lock_Release_and_ISR_enable( &( _lock )->lock, _isr_cookie ) +#else + #define rtems_interrupt_lock_release( _lock, _isr_cookie ) \ + do { \ + (void) _lock; \ + rtems_interrupt_enable( _isr_cookie ); \ + } while (0) +#endif + +/** + * @brief Acquires an interrupt lock in the corresponding interrupt service + * routine. + * + * The interrupt status will remain unchanged. On SMP configurations this + * function acquires a SMP lock. + * + * In case the corresponding interrupt service routine can be interrupted by + * higher priority interrupts and these interrupts enter the critical section + * protected by this lock, then the result is unpredictable. + * + * @see rtems_interrupt_lock_release_isr(). + */ +#if defined( RTEMS_SMP ) + #define rtems_interrupt_lock_acquire_isr( _lock ) \ + _SMP_lock_Acquire( &( _lock )->lock ) +#else + #define rtems_interrupt_lock_acquire_isr( _lock ) \ + do { \ + (void) _lock; \ + } while (0) +#endif + +/** + * @brief Releases an interrupt lock in the corresponding interrupt service + * routine. + * + * The interrupt status will remain unchanged. On SMP configurations this + * function releases a SMP lock. + * + * @see rtems_interrupt_lock_acquire_isr(). + */ +#if defined( RTEMS_SMP ) + #define rtems_interrupt_lock_release_isr( _lock ) \ + _SMP_lock_Release( &( _lock )->lock ) +#else + #define rtems_interrupt_lock_release_isr( _lock ) \ + do { \ + (void) _lock; \ + } while (0) +#endif + +/** @} */ + #ifdef __cplusplus } #endif diff --git a/doc/user/intr.t b/doc/user/intr.t index dd5c9c80d5..b6a58dcb1f 100644 --- a/doc/user/intr.t +++ b/doc/user/intr.t @@ -21,6 +21,11 @@ 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_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 +@item @code{@value{DIRPREFIX}interrupt_lock_acquire_isr} - Acquire an ISR Lock from ISR +@item @code{@value{DIRPREFIX}interrupt_lock_release_isr} - Release an ISR Lock from ISR @item @code{@value{DIRPREFIX}interrupt_is_in_progress} - Is an ISR in Progress @end itemize @@ -194,6 +199,10 @@ implementation error to use RTEMS_SELF from an ISR. @item rtems_interrupt_enable @item rtems_interrupt_disable @item rtems_interrupt_flash +@item rtems_interrupt_lock_acquire +@item rtems_interrupt_lock_release +@item rtems_interrupt_lock_acquire_isr +@item rtems_interrupt_lock_release_isr @item rtems_interrupt_is_in_progress @item rtems_interrupt_catch @end itemize @@ -453,6 +462,167 @@ and will be redisabled when this directive returns to the caller. This directive will not cause the calling task to be preempted. +@c +@c +@c +@page +@subsection INTERRUPT_LOCK_INITIALIZE - Initialize an ISR Lock + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_interrupt_lock_initialize +@example +void rtems_interrupt_lock_initialize( + rtems_interrupt_lock *lock +); +@end example +@end ifset + +@subheading DIRECTIVE STATUS CODES: + +NONE + +@subheading DESCRIPTION: + +Initializes an interrupt lock. + +@subheading NOTES: + +Concurrent initialization leads to unpredictable results. + +@c +@c +@c +@page +@subsection INTERRUPT_LOCK_ACQUIRE - Acquire an ISR Lock + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_interrupt_lock_acquire +@example +void rtems_interrupt_lock_acquire( + rtems_interrupt_lock *lock, + rtems_interrupt_level level +); +@end example +@end ifset + +@subheading DIRECTIVE STATUS CODES: + +NONE + +@subheading DESCRIPTION: + +Interrupts will be disabled. On SMP configurations this directive acquires a +SMP lock. + +@subheading NOTES: + +This directive will not cause the calling thread to be preempted. This +directive can be used in thread and interrupt context. + +@c +@c +@c +@page +@subsection INTERRUPT_LOCK_RELEASE - Release an ISR Lock + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_interrupt_lock_release +@example +void rtems_interrupt_lock_release( + rtems_interrupt_lock *lock, + rtems_interrupt_level level +); +@end example +@end ifset + +@subheading DIRECTIVE STATUS CODES: + +NONE + +@subheading DESCRIPTION: + +The interrupt status will be restored. On SMP configurations this directive +releases a SMP lock. + +@subheading NOTES: + +This directive will not cause the calling thread to be preempted. This +directive can be used in thread and interrupt context. + +@c +@c +@c +@page +@subsection INTERRUPT_LOCK_ACQUIRE_ISR - Acquire an ISR Lock from ISR + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_interrupt_lock_acquire_isr +@example +void rtems_interrupt_lock_acquire_isr( + rtems_interrupt_lock *lock, + rtems_interrupt_level level +); +@end example +@end ifset + +@subheading DIRECTIVE STATUS CODES: + +NONE + +@subheading DESCRIPTION: + +The interrupt status will remain unchanged. On SMP configurations this +directive acquires a SMP lock. + +In case the corresponding interrupt service routine can be interrupted by +higher priority interrupts and these interrupts enter the critical section +protected by this lock, then the result is unpredictable. + +@subheading NOTES: + +This directive should be called from the corresponding interrupt service +routine. + +@c +@c +@c +@page +@subsection INTERRUPT_LOCK_RELEASE_ISR - Release an ISR Lock from ISR + +@subheading CALLING SEQUENCE: + +@ifset is-C +@findex rtems_interrupt_lock_release_isr +@example +void rtems_interrupt_lock_release_isr( + rtems_interrupt_lock *lock, + rtems_interrupt_level level +); +@end example +@end ifset + +@subheading DIRECTIVE STATUS CODES: + +NONE + +@subheading DESCRIPTION: + +The interrupt status will remain unchanged. On SMP configurations this +directive releases a SMP lock. + +@subheading NOTES: + +This directive should be called from the corresponding interrupt service +routine. + @c @c @c diff --git a/testsuites/sptests/sp37/init.c b/testsuites/sptests/sp37/init.c index 870316acfb..956c91d936 100644 --- a/testsuites/sptests/sp37/init.c +++ b/testsuites/sptests/sp37/init.c @@ -43,6 +43,21 @@ rtems_timer_service_routine test_isr_in_progress( ); /* test bodies */ + +static void test_interrupt_locks( void ) +{ + rtems_interrupt_lock lock = RTEMS_INTERRUPT_LOCK_INITIALIZER; + rtems_interrupt_level level; + + rtems_interrupt_lock_initialize( &lock ); + + rtems_interrupt_lock_acquire( &lock, level ); + rtems_interrupt_lock_release( &lock, level ); + + rtems_interrupt_lock_acquire_isr( &lock ); + rtems_interrupt_lock_release_isr( &lock ); +} + void test_interrupt_inline(void) { rtems_interrupt_level level; @@ -318,6 +333,8 @@ rtems_task Init( check_isr_worked( "body", isr_in_progress_body ); + test_interrupt_locks(); + puts( "*** END OF TEST 37 ***" ); rtems_test_exit( 0 ); } -- cgit v1.2.3