summaryrefslogblamecommitdiffstats
path: root/cpukit/include/rtems/score/smplock.h
blob: b1f5a6de28af5327e8f76b8a289eb3c9ab9aa7a1 (plain) (tree)
1
2
3
4
5
6
7
8
9
   
        
  
                             
  
                      


   

                                                   
  
                                                


                                                          
                                        

   

                              
 

                                
   
                                        
  
                      
  




                                                                              
  


                                                                              

     
   
 














                                      



                                                    
   


                           
                                      
                        













                                                                              
                            

                       






                                                               
                        

                                          
                            
                                       
      

                   
                        
                           

      


                                                                 
                                                    





                                          
                          

                                                      
                              




                                                                       
 















                                                    
   
                                  


                                                            
                                        

                                                                           
   
                                         

                          
                        
  
     

                                            
      




                                                                     


   



                                                         
                                        
   
                                         
                                                 
     

                                   
      
 


















                                                                       










                                                                              



                                            
 










                                        
                                     
      


   





                                                                              

                                                                           

        




                           
                                            



                           


                                                    
                                                 

                                  
                 

                           
                       

                           




                               

                                                                           

        
                                         



                           



                                            
 
                                                            



                           

                                            


   
                                                        
  

                                                                           
        
   




                                       
                                                           



                           

                                            
 

   
                                                       
  

                                                                           
        
   
                                         



                                      



                                                           
 
                        








                                                                          
         


                  
                        
 
                      
 
                                   
/**
 * @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 <rtems/score/cpuopts.h>

/**
 * @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 <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 */

#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 */