rtems: Add interrupt locks

Interrupt locks are low-level lock to protect critical sections accessed
by threads and interrupt service routines.
This commit is contained in:
Sebastian Huber
2013-06-12 16:11:24 +02:00
parent 3ccce23aa4
commit c7bc6d44cb
3 changed files with 322 additions and 0 deletions
+135
View File
@@ -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
+170
View File
@@ -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
+17
View File
@@ -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 );
}