/** * @file * * @ingroup RTEMSScoreSMPLock * * @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 /** * @defgroup RTEMSScoreSMPLock SMP Locks * * @ingroup RTEMSScore * * @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_SMP) #include #include #include #if defined(RTEMS_DEBUG) #include #include #endif #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #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 /** * @brief Sets the name of an SMP lock. * * @param[out] lock The SMP lock control. * @param name The name for the SMP lock statistics. This name must be * persistent throughout the life time of this statistics block. */ static inline void _SMP_lock_Set_name( SMP_lock_Control *lock, const char *name ) { #if defined(RTEMS_PROFILING) lock->Stats.name = name; #else (void) name; #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 */