mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-08-21 07:08:43 +08:00
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:
@@ -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
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user