diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-06-10 11:14:35 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2013-06-12 16:11:24 +0200 |
commit | c7bc6d44cbd563c72afb7e9355c7350c16acb27b (patch) | |
tree | 78e4fc2849538285582b58e84ca03c0c0fc21433 | |
parent | score: Always provide <rtems/score/smplock.h> (diff) | |
download | rtems-c7bc6d44cbd563c72afb7e9355c7350c16acb27b.tar.bz2 |
rtems: Add interrupt locks
Interrupt locks are low-level lock to protect critical sections accessed
by threads and interrupt service routines.
Diffstat (limited to '')
-rw-r--r-- | cpukit/rtems/include/rtems/rtems/intr.h | 135 | ||||
-rw-r--r-- | doc/user/intr.t | 170 | ||||
-rw-r--r-- | testsuites/sptests/sp37/init.c | 17 |
3 files changed, 322 insertions, 0 deletions
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 <rtems/score/isr.h> +#include <rtems/score/smplock.h> /** * @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 @@ -457,6 +466,167 @@ This directive will not cause the calling task to be preempted. @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 +@page @subsection INTERRUPT_IS_IN_PROGRESS - Is an ISR in Progress @cindex is interrupt in progress 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 ); } |