Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:13

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSScoreSMPLock
0007  *
0008  * @brief This header file provides the main interfaces of the
0009  *   @ref RTEMSScoreSMPLock.
0010  */
0011 
0012 /*
0013  * COPYRIGHT (c) 1989-2011.
0014  * On-Line Applications Research Corporation (OAR).
0015  *
0016  * Copyright (C) 2013, 2016 embedded brains GmbH & Co. KG
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifndef _RTEMS_SCORE_SMPLOCK_H
0041 #define _RTEMS_SCORE_SMPLOCK_H
0042 
0043 #include <rtems/score/cpuopts.h>
0044 
0045 /**
0046  * @defgroup RTEMSScoreSMPLock SMP Locks
0047  *
0048  * @ingroup RTEMSScore
0049  *
0050  * @brief This group contains the SMP lock implementation.
0051  *
0052  * The SMP lock provides mutual exclusion in SMP systems at the lowest level.
0053  *
0054  * The SMP lock is implemented as a ticket lock.  This provides fairness in
0055  * case of concurrent lock attempts.
0056  *
0057  * This SMP lock API uses a local context for acquire and release pairs.  Such
0058  * a context may be used to implement for example the Mellor-Crummey and Scott
0059  * (MCS) locks in the future.
0060  *
0061  * @{
0062  */
0063 
0064 #if defined(RTEMS_SMP)
0065 
0066 #include <rtems/score/smplockstats.h>
0067 #include <rtems/score/smplockticket.h>
0068 #include <rtems/score/isrlevel.h>
0069 
0070 #if defined(RTEMS_DEBUG)
0071 #include <rtems/score/assert.h>
0072 #include <rtems/score/smp.h>
0073 #endif
0074 
0075 #ifdef __cplusplus
0076 extern "C" {
0077 #endif /* __cplusplus */
0078 
0079 #if defined(RTEMS_DEBUG) || defined(RTEMS_PROFILING)
0080 #define RTEMS_SMP_LOCK_DO_NOT_INLINE
0081 #endif
0082 
0083 /**
0084  * @brief SMP lock control.
0085  */
0086 typedef struct {
0087   SMP_ticket_lock_Control Ticket_lock;
0088 #if defined(RTEMS_DEBUG)
0089   /**
0090    * @brief The index of the owning processor of this lock.
0091    *
0092    * The processor index is used instead of the executing thread, so that this
0093    * works in interrupt and system initialization context.  It is assumed that
0094    * thread dispatching is disabled in SMP lock critical sections.
0095    *
0096    * In case the lock is free, then the value of this field is
0097    * SMP_LOCK_NO_OWNER.
0098    *
0099    * @see _SMP_lock_Is_owner().
0100    */
0101   uint32_t owner;
0102 #endif
0103 #if defined(RTEMS_PROFILING)
0104   SMP_lock_Stats Stats;
0105 #endif
0106 } SMP_lock_Control;
0107 
0108 /**
0109  * @brief Local SMP lock context for acquire and release pairs.
0110  */
0111 typedef struct {
0112   ISR_Level isr_level;
0113 #if defined(RTEMS_DEBUG)
0114   SMP_lock_Control *lock_used_for_acquire;
0115 #endif
0116 #if defined(RTEMS_PROFILING)
0117   SMP_lock_Stats_context Stats_context;
0118 #endif
0119 } SMP_lock_Context;
0120 
0121 #if defined(RTEMS_DEBUG)
0122 #define SMP_LOCK_NO_OWNER 0
0123 #endif
0124 
0125 /**
0126  * @brief SMP lock control initializer for static initialization.
0127  */
0128 #if defined(RTEMS_DEBUG) && defined(RTEMS_PROFILING)
0129   #define SMP_LOCK_INITIALIZER( name ) \
0130     { \
0131       SMP_TICKET_LOCK_INITIALIZER, \
0132       SMP_LOCK_NO_OWNER, \
0133       SMP_LOCK_STATS_INITIALIZER( name ) \
0134     }
0135 #elif defined(RTEMS_DEBUG)
0136   #define SMP_LOCK_INITIALIZER( name ) \
0137     { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_NO_OWNER }
0138 #elif defined(RTEMS_PROFILING)
0139   #define SMP_LOCK_INITIALIZER( name ) \
0140     { SMP_TICKET_LOCK_INITIALIZER, SMP_LOCK_STATS_INITIALIZER( name ) }
0141 #else
0142   #define SMP_LOCK_INITIALIZER( name ) { SMP_TICKET_LOCK_INITIALIZER }
0143 #endif
0144 
0145 /**
0146  * @brief Initializes the SMP lock with the given name.
0147  *
0148  * @param[in, out] lock The lock to initialize.
0149  */
0150 static inline void _SMP_lock_Initialize_inline(
0151   SMP_lock_Control *lock,
0152   const char       *name
0153 )
0154 {
0155   _SMP_ticket_lock_Initialize( &lock->Ticket_lock );
0156 #if defined(RTEMS_DEBUG)
0157   lock->owner = SMP_LOCK_NO_OWNER;
0158 #endif
0159 #if defined(RTEMS_PROFILING)
0160   _SMP_lock_Stats_initialize( &lock->Stats, name );
0161 #else
0162   (void) name;
0163 #endif
0164 }
0165 
0166 /**
0167  * @brief Initializes an SMP lock.
0168  *
0169  * Concurrent initialization leads to unpredictable results.
0170  *
0171  * @param[in, out] lock The SMP lock control.
0172  * @param name The name for the SMP lock statistics.  This name must be
0173  * persistent throughout the life time of this statistics block.
0174  */
0175 #if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
0176 void _SMP_lock_Initialize(
0177   SMP_lock_Control *lock,
0178   const char       *name
0179 );
0180 #else
0181 #define _SMP_lock_Initialize( lock, name ) \
0182   _SMP_lock_Initialize_inline( lock, name )
0183 #endif
0184 
0185 /**
0186  * @brief Destroys the SMP lock.
0187  *
0188  * @param[in, out] lock The lock to destroy.
0189  */
0190 static inline void _SMP_lock_Destroy_inline( SMP_lock_Control *lock )
0191 {
0192   _SMP_ticket_lock_Destroy( &lock->Ticket_lock );
0193   _SMP_lock_Stats_destroy( &lock->Stats );
0194 }
0195 
0196 /**
0197  * @brief Destroys an SMP lock.
0198  *
0199  * Concurrent destruction leads to unpredictable results.
0200  *
0201  * @param[in, out] lock The SMP lock control.
0202  */
0203 #if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
0204 void _SMP_lock_Destroy( SMP_lock_Control *lock );
0205 #else
0206 #define _SMP_lock_Destroy( lock ) \
0207   _SMP_lock_Destroy_inline( lock )
0208 #endif
0209 
0210 /**
0211  * @brief Sets the name of an SMP lock.
0212  *
0213  * @param[out] lock The SMP lock control.
0214  * @param name The name for the SMP lock statistics.  This name must be
0215  *   persistent throughout the life time of this statistics block.
0216  */
0217 static inline void _SMP_lock_Set_name(
0218   SMP_lock_Control *lock,
0219   const char       *name
0220 )
0221 {
0222 #if defined(RTEMS_PROFILING)
0223   lock->Stats.name = name;
0224 #else
0225   (void) lock;
0226   (void) name;
0227 #endif
0228 }
0229 
0230 /**
0231  * @brief Gets my index.
0232  *
0233  * @return The current processor index + 1.
0234  */
0235 #if defined(RTEMS_DEBUG)
0236 static inline uint32_t _SMP_lock_Who_am_I( void )
0237 {
0238   /*
0239    * The CPU index starts with zero.  Increment it by one, to allow global SMP
0240    * locks to reside in the BSS section.
0241    */
0242   return _SMP_Get_current_processor() + 1;
0243 }
0244 #endif
0245 
0246 /**
0247  * @brief Acquires the lock inline.
0248  *
0249  * @param[in, out] lock The lock to acquire.
0250  * @param[in, out] context The lock context.
0251  */
0252 static inline void _SMP_lock_Acquire_inline(
0253   SMP_lock_Control *lock,
0254   SMP_lock_Context *context
0255 )
0256 {
0257 #if defined(RTEMS_DEBUG)
0258   context->lock_used_for_acquire = lock;
0259 #else
0260   (void) context;
0261 #endif
0262   _SMP_ticket_lock_Acquire(
0263     &lock->Ticket_lock,
0264     &lock->Stats,
0265     &context->Stats_context
0266   );
0267 #if defined(RTEMS_DEBUG)
0268   lock->owner = _SMP_lock_Who_am_I();
0269 #endif
0270 }
0271 
0272 /**
0273  * @brief Acquires an SMP lock.
0274  *
0275  * This function will not disable interrupts.  The caller must ensure that the
0276  * current thread of execution is not interrupted indefinite once it obtained
0277  * the SMP lock.
0278  *
0279  * @param[in, out] lock The SMP lock control.
0280  * @param[in, out] context The local SMP lock context for an acquire and release
0281  * pair.
0282  */
0283 void _SMP_lock_Acquire(
0284   SMP_lock_Control *lock,
0285   SMP_lock_Context *context
0286 );
0287 
0288 /**
0289  * @brief Releases an SMP lock.
0290  *
0291  * @param[in, out] lock The lock to release.
0292  * @param[in, out] context The lock context.
0293  */
0294 static inline void _SMP_lock_Release_inline(
0295   SMP_lock_Control *lock,
0296   SMP_lock_Context *context
0297 )
0298 {
0299 #if defined(RTEMS_DEBUG)
0300   _Assert( context->lock_used_for_acquire == lock );
0301   context->lock_used_for_acquire = NULL;
0302   _Assert( lock->owner == _SMP_lock_Who_am_I() );
0303   lock->owner = SMP_LOCK_NO_OWNER;
0304 #else
0305   (void) context;
0306 #endif
0307   _SMP_ticket_lock_Release(
0308     &lock->Ticket_lock,
0309     &context->Stats_context
0310   );
0311 }
0312 
0313 /**
0314  * @brief Releases an SMP lock.
0315  *
0316  * @param[in, out] lock The SMP lock control.
0317  * @param[in, out] context The local SMP lock context for an acquire and release
0318  * pair.
0319  */
0320 #if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
0321 void _SMP_lock_Release(
0322   SMP_lock_Control *lock,
0323   SMP_lock_Context *context
0324 );
0325 #else
0326 #define _SMP_lock_Release( lock, context ) \
0327   _SMP_lock_Release_inline( lock, context )
0328 #endif
0329 
0330 /**
0331  * @brief Disables interrupts and acquires the SMP lock
0332  *
0333  * @param[in, out] lock The lock to acquire.
0334  * @param[in, out] context The lock context.
0335  */
0336 static inline void _SMP_lock_ISR_disable_and_acquire_inline(
0337   SMP_lock_Control *lock,
0338   SMP_lock_Context *context
0339 )
0340 {
0341   _ISR_Local_disable( context->isr_level );
0342   _SMP_lock_Acquire_inline( lock, context );
0343 }
0344 
0345 /**
0346  * @brief Disables interrupts and acquires the SMP lock.
0347  *
0348  * @param[in, out] lock The SMP lock control.
0349  * @param[in, out] context The local SMP lock context for an acquire and release
0350  * pair.
0351  */
0352 void _SMP_lock_ISR_disable_and_acquire(
0353   SMP_lock_Control *lock,
0354   SMP_lock_Context *context
0355 );
0356 
0357 /**
0358  * @brief Releases the SMP lock and enables interrupts.
0359  *
0360  * @param[in, out] lock The SMP lock to release.
0361  * @param[in, out] context The lock context.
0362  */
0363 static inline void _SMP_lock_Release_and_ISR_enable_inline(
0364   SMP_lock_Control *lock,
0365   SMP_lock_Context *context
0366 )
0367 {
0368   _SMP_lock_Release_inline( lock, context );
0369   _ISR_Local_enable( context->isr_level );
0370 }
0371 
0372 /**
0373  * @brief Releases the SMP lock and enables interrupts.
0374  *
0375  * @param[in, out] lock The SMP lock control.
0376  * @param[in, out] context The local SMP lock context for an acquire and release
0377  * pair.
0378  */
0379 #if defined(RTEMS_SMP_LOCK_DO_NOT_INLINE)
0380 void _SMP_lock_Release_and_ISR_enable(
0381   SMP_lock_Control *lock,
0382   SMP_lock_Context *context
0383 );
0384 #else
0385 #define _SMP_lock_Release_and_ISR_enable( lock, context ) \
0386   _SMP_lock_Release_and_ISR_enable_inline( lock, context )
0387 #endif
0388 
0389 #if defined(RTEMS_DEBUG)
0390 /**
0391  * @brief Checks if the SMP lock is owned by the current processor.
0392  *
0393  * @param lock The SMP lock control.
0394  *
0395  * @retval true The SMP lock is owned by the current processor.
0396  * @retval false The SMP lock is not owned by the current processor.
0397  */
0398 bool _SMP_lock_Is_owner( const SMP_lock_Control *lock );
0399 #endif
0400 
0401 /** @} */
0402 
0403 #ifdef __cplusplus
0404 }
0405 #endif /* __cplusplus */
0406 
0407 #endif /* RTEMS_SMP */
0408 
0409 #endif /* _RTEMS_SCORE_SMPLOCK_H */