diff options
Diffstat (limited to 'cpukit/include/rtems/score/smplock.h')
-rw-r--r-- | cpukit/include/rtems/score/smplock.h | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/cpukit/include/rtems/score/smplock.h b/cpukit/include/rtems/score/smplock.h new file mode 100644 index 0000000000..a156edfd92 --- /dev/null +++ b/cpukit/include/rtems/score/smplock.h @@ -0,0 +1,327 @@ +/** + * @file + * + * @ingroup ScoreSMPLock + * + * @brief SMP Lock API + */ + +/* + * COPYRIGHT (c) 1989-2011. + * On-Line Applications Research Corporation (OAR). + * + * Copyright (c) 2013, 2016 embedded brains GmbH + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_SMPLOCK_H +#define _RTEMS_SCORE_SMPLOCK_H + +#include <rtems/score/cpuopts.h> + +#if defined(RTEMS_SMP) + +#include <rtems/score/smplockstats.h> +#include <rtems/score/smplockticket.h> +#include <rtems/score/isrlevel.h> + +#if defined(RTEMS_DEBUG) +#include <rtems/score/assert.h> +#include <rtems/score/smp.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup ScoreSMPLock SMP Locks + * + * @ingroup Score + * + * @brief The SMP lock provides mutual exclusion for SMP systems at the lowest + * level. + * + * The SMP lock is implemented as a ticket lock. This provides fairness in + * case of concurrent lock attempts. + * + * This SMP lock API uses a local context for acquire and release pairs. Such + * a context may be used to implement for example the Mellor-Crummey and Scott + * (MCS) locks in the future. + * + * @{ + */ + +#if defined(RTEMS_DEBUG) || defined(RTEMS_PROFILING) +#define RTEMS_SMP_LOCK_DO_NOT_INLINE +#endif + +/** + * @brief SMP lock control. + */ +typedef struct { + SMP_ticket_lock_Control Ticket_lock; +#if defined(RTEMS_DEBUG) + /** + * @brief The index of the owning processor of this lock. + * + * The processor index is used instead of the executing thread, so that this + * works in interrupt and system initialization context. It is assumed that + * thread dispatching is disabled in SMP lock critical sections. + * + * In case the lock is free, then the value of this field is + * SMP_LOCK_NO_OWNER. + * + * @see _SMP_lock_Is_owner(). + */ + uint32_t owner; +#endif +#if defined(RTEMS_PROFILING) + SMP_lock_Stats Stats; +#endif +} SMP_lock_Control; + +/** + * @brief Local SMP lock context for acquire and release pairs. + */ +typedef struct { + ISR_Level isr_level; +#if defined(RTEMS_DEBUG) + SMP_lock_Control *lock_used_for_acquire; +#endif +#if defined(RTEMS_PROFILING) + SMP_lock_Stats_context Stats_context; +#endif +} SMP_lock_Context; + +#if defined(RTEMS_DEBUG) +#define SMP_LOCK_NO_OWNER 0 +#endif + +/** + * @brief SMP lock control initializer for static initialization. + */ +#if defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING) + #define SMP_LOCK_INITIALIZER( name ) \ + { \ + SMP_TICKET_LOCK_INITIALIZER, \ + SMP_LOCK_NO_OWNER, \ + SMP_LOCK_STATS_INITIALIZER( name ) \ + } +#elif defined(RTEMS_DEBUG) + #define SMP_LOCK_INITIALIZER( name ) \ + { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_NO_OWNER } +#elif defined(RTEMS_PROFILING) + #define SMP_LOCK_INITIALIZER( name ) \ + { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_STATS_INITIALIZER( name ) } +#else + #define SMP_LOCK_INITIALIZER( name ) { SMP_TICKET_LOCK_INITIALIZER } +#endif + +static inline void _SMP_lock_Initialize_inline( + SMP_lock_Control *lock, + const char *name +) +{ + _SMP_ticket_lock_Initialize( &lock->Ticket_lock ); +#if defined(RTEMS_DEBUG) + lock->owner = SMP_LOCK_NO_OWNER; +#endif +#if defined(RTEMS_PROFILING) + _SMP_lock_Stats_initialize( &lock->Stats, name ); +#else + (void) name; +#endif +} + +/** + * @brief Initializes an SMP lock. + * + * Concurrent initialization leads to unpredictable results. + * + * @param[in] lock The SMP lock control. + * @param[in] name The name for the SMP lock statistics. This name must be + * persistent throughout the life time of this statistics block. + */ +#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE) +void _SMP_lock_Initialize( + SMP_lock_Control *lock, + const char * name +); +#else +#define _SMP_lock_Initialize( lock, name ) \ + _SMP_lock_Initialize_inline( lock, name ) +#endif + +static inline void _SMP_lock_Destroy_inline( SMP_lock_Control *lock ) +{ + _SMP_ticket_lock_Destroy( &lock->Ticket_lock ); + _SMP_lock_Stats_destroy( &lock->Stats ); +} + +/** + * @brief Destroys an SMP lock. + * + * Concurrent destruction leads to unpredictable results. + * + * @param[in] lock The SMP lock control. + */ +#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE) +void _SMP_lock_Destroy( SMP_lock_Control *lock ); +#else +#define _SMP_lock_Destroy( lock ) \ + _SMP_lock_Destroy_inline( lock ) +#endif + +#if defined(RTEMS_DEBUG) +static inline uint32_t _SMP_lock_Who_am_I( void ) +{ + /* + * The CPU index starts with zero. Increment it by one, to allow global SMP + * locks to reside in the BSS section. + */ + return _SMP_Get_current_processor() + 1; +} +#endif + +static inline void _SMP_lock_Acquire_inline( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ +#if defined(RTEMS_DEBUG) + context->lock_used_for_acquire = lock; +#else + (void) context; +#endif + _SMP_ticket_lock_Acquire( + &lock->Ticket_lock, + &lock->Stats, + &context->Stats_context + ); +#if defined(RTEMS_DEBUG) + lock->owner = _SMP_lock_Who_am_I(); +#endif +} + +/** + * @brief Acquires an SMP lock. + * + * This function will not disable interrupts. The caller must ensure that the + * current thread of execution is not interrupted indefinite once it obtained + * the SMP lock. + * + * @param[in] lock The SMP lock control. + * @param[in] context The local SMP lock context for an acquire and release + * pair. + */ +void _SMP_lock_Acquire( + SMP_lock_Control *lock, + SMP_lock_Context *context +); + +static inline void _SMP_lock_Release_inline( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ +#if defined(RTEMS_DEBUG) + _Assert( context->lock_used_for_acquire == lock ); + context->lock_used_for_acquire = NULL; + _Assert( lock->owner == _SMP_lock_Who_am_I() ); + lock->owner = SMP_LOCK_NO_OWNER; +#else + (void) context; +#endif + _SMP_ticket_lock_Release( + &lock->Ticket_lock, + &context->Stats_context + ); +} + +/** + * @brief Releases an SMP lock. + * + * @param[in] lock The SMP lock control. + * @param[in] context The local SMP lock context for an acquire and release + * pair. + */ +#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE) +void _SMP_lock_Release( + SMP_lock_Control *lock, + SMP_lock_Context *context +); +#else +#define _SMP_lock_Release( lock, context ) \ + _SMP_lock_Release_inline( lock, context ) +#endif + +static inline void _SMP_lock_ISR_disable_and_acquire_inline( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ + _ISR_Local_disable( context->isr_level ); + _SMP_lock_Acquire_inline( lock, context ); +} + +/** + * @brief Disables interrupts and acquires the SMP lock. + * + * @param[in] lock The SMP lock control. + * @param[in] context The local SMP lock context for an acquire and release + * pair. + */ +void _SMP_lock_ISR_disable_and_acquire( + SMP_lock_Control *lock, + SMP_lock_Context *context +); + +static inline void _SMP_lock_Release_and_ISR_enable_inline( + SMP_lock_Control *lock, + SMP_lock_Context *context +) +{ + _SMP_lock_Release_inline( lock, context ); + _ISR_Local_enable( context->isr_level ); +} + +/** + * @brief Releases the SMP lock and enables interrupts. + * + * @param[in] lock The SMP lock control. + * @param[in] context The local SMP lock context for an acquire and release + * pair. + */ +#if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE) +void _SMP_lock_Release_and_ISR_enable( + SMP_lock_Control *lock, + SMP_lock_Context *context +); +#else +#define _SMP_lock_Release_and_ISR_enable( lock, context ) \ + _SMP_lock_Release_and_ISR_enable_inline( lock, context ) +#endif + +#if defined(RTEMS_DEBUG) +/** + * @brief Returns true, if the SMP lock is owned by the current processor, + * otherwise false. + * + * @param[in] lock The SMP lock control. + */ +bool _SMP_lock_Is_owner( const SMP_lock_Control *lock ); +#endif + +/**@}*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* RTEMS_SMP */ + +#endif /* _RTEMS_SCORE_SMPLOCK_H */ |