Changeset e358088 in rtems


Ignore:
Timestamp:
May 28, 2013, 8:54:46 AM (6 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, master
Children:
bbed1866
Parents:
7c5ceea5
git-author:
Sebastian Huber <sebastian.huber@…> (05/28/13 08:54:46)
git-committer:
Sebastian Huber <sebastian.huber@…> (05/31/13 13:20:32)
Message:

smp: New SMP lock API

Move the SMP lock implementation to the CPU port. An optimal SMP lock
implementation is highly architecture dependent. For example the memory
models may be fundamentally different.

The new SMP lock API has a flaw. It does not provide the ability to use
a local context for acquire and release pairs. Such a context is
necessary to implement for example the Mellor-Crummey and Scott (MCS)
locks. The SMP lock is currently used in _Thread_Disable_dispatch() and
_Thread_Enable_dispatch() and makes them to a giant lock acquire and
release. Since these functions do not pass state information via a
local context there is currently no use case for such a feature.

Location:
cpukit/score
Files:
3 added
1 deleted
14 edited

Legend:

Unmodified
Added
Removed
  • cpukit/score/Makefile.am

    r7c5ceea5 re358088  
    136136
    137137if HAS_SMP
    138 libscore_a_SOURCES += src/isrsmp.c src/smp.c src/smplock.c \
     138libscore_a_SOURCES += src/isrsmp.c src/smp.c \
    139139    src/schedulersimplesmpblock.c src/schedulersimplesmpschedule.c \
    140140    src/schedulersimplesmpunblock.c src/schedulersimplesmptick.c
  • cpukit/score/cpu/i386/Makefile.am

    r7c5ceea5 re358088  
    1212include_rtems_score_HEADERS += rtems/score/idtr.h
    1313include_rtems_score_HEADERS += rtems/score/cpuatomic.h
     14include_rtems_score_HEADERS += rtems/score/cpusmplock.h
    1415
    1516noinst_LIBRARIES = libscorecpu.a
  • cpukit/score/cpu/i386/preinstall.am

    r7c5ceea5 re358088  
    5656PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
    5757
     58$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
     59        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
     60PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
     61
  • cpukit/score/cpu/i386/rtems/score/cpu.h

    r7c5ceea5 re358088  
    456456     _CPU_Context_restore( (_the_context) );
    457457
    458   /* address space 1 is uncacheable */
    459   #define SMP_CPU_SWAP( _address, _value, _previous ) \
    460     do { \
    461       asm volatile("lock; xchgl %0, %1" : \
    462         "+m" (*_address), "=a" (_previous) : \
    463         "1" (_value) : \
    464         "cc"); \
    465     } while (0)
    466 
    467458  static inline void _CPU_Processor_event_broadcast( void )
    468459  {
  • cpukit/score/cpu/no_cpu/Makefile.am

    r7c5ceea5 re358088  
    99include_rtems_score_HEADERS += rtems/score/cpu_asm.h
    1010include_rtems_score_HEADERS += rtems/score/types.h
     11include_rtems_score_HEADERS += rtems/score/cpusmplock.h
    1112
    1213noinst_LIBRARIES = libscorecpu.a
  • cpukit/score/cpu/no_cpu/preinstall.am

    r7c5ceea5 re358088  
    4444PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/types.h
    4545
     46$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
     47        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
     48PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
     49
  • cpukit/score/cpu/sparc/Makefile.am

    r7c5ceea5 re358088  
    99include_rtems_score_HEADERS += rtems/score/types.h
    1010include_rtems_score_HEADERS += rtems/score/cpuatomic.h
     11include_rtems_score_HEADERS += rtems/score/cpusmplock.h
    1112
    1213noinst_LIBRARIES = libscorecpu.a
  • cpukit/score/cpu/sparc/preinstall.am

    r7c5ceea5 re358088  
    4444PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpuatomic.h
    4545
     46$(PROJECT_INCLUDE)/rtems/score/cpusmplock.h: rtems/score/cpusmplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
     47        $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
     48PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/cpusmplock.h
     49
  • cpukit/score/cpu/sparc/rtems/score/cpu.h

    r7c5ceea5 re358088  
    11871187  );
    11881188
    1189   /**
    1190    * Macro to access memory and bypass the cache.
    1191    *
    1192    * NOTE: address space 1 is uncacheable
    1193    */
    1194   #define SMP_CPU_SWAP( _address, _value, _previous ) \
    1195     do { \
    1196       register unsigned int _val = _value; \
    1197       asm volatile( \
    1198         "swapa [%2] %3, %0" : \
    1199         "=r" (_val) : \
    1200         "0" (_val), \
    1201         "r" (_address), \
    1202         "i" (1) \
    1203       ); \
    1204       _previous = _val; \
    1205     } while (0)
    1206 
    12071189  static inline void _CPU_Processor_event_broadcast( void )
    12081190  {
  • cpukit/score/include/rtems/score/percpu.h

    r7c5ceea5 re358088  
    168168  #if defined(RTEMS_SMP)
    169169    /** This element is used to lock this structure */
    170     SMP_lock_spinlock_simple_Control lock;
     170    SMP_lock_Control lock;
    171171
    172172    /**
  • cpukit/score/include/rtems/score/smplock.h

    r7c5ceea5 re358088  
    11/**
    2  *  @file  rtems/score/smplock.h
     2 * @file
    33 *
    4  *  @brief Interface for Atomic Locks
     4 * @ingroup ScoreSMPLock
    55 *
    6  *  This include file defines the interface for atomic locks
    7  *  which can be used in multiprocessor configurations.
     6 * @brief SMP Lock API
    87 */
    98
    109/*
    11  *  COPYRIGHT (c) 1989-2011.
    12  *  On-Line Applications Research Corporation (OAR).
     10 * COPYRIGHT (c) 1989-2011.
     11 * On-Line Applications Research Corporation (OAR).
    1312 *
    14  *  The license and distribution terms for this file may be
    15  *  found in the file LICENSE in this distribution or at
    16  *  http://www.rtems.com/license/LICENSE.
     13 * Copyright (c) 2013 embedded brains GmbH
     14 *
     15 * The license and distribution terms for this file may be
     16 * found in the file LICENSE in this distribution or at
     17 * http://www.rtems.com/license/LICENSE.
    1718 */
    1819
    19 #ifndef _RTEMS_LOCK_H
    20 #define _RTEMS_LOCK_H
     20#ifndef _RTEMS_SCORE_SMPLOCK_H
     21#define _RTEMS_SCORE_SMPLOCK_H
    2122
     23#include <rtems/score/cpusmplock.h>
    2224#include <rtems/score/isr.h>
    23 
    24 /**
    25  *  @defgroup RTEMS Lock Interface
    26  *
    27  *  @ingroup Score
    28  *
    29  */
    30 
    31 /**@{*/
    3225
    3326#ifdef __cplusplus
    3427extern "C" {
    35 #endif
     28#endif /* __cplusplus */
    3629
    3730/**
    38  *  This type is used to lock elements for atomic access.
    39  *  This spinlock is a simple non-nesting spinlock, and
    40  *  may be used for short non-nesting accesses.
     31 * @defgroup ScoreSMPLock SMP Locks
     32 *
     33 * @ingroup Score
     34 *
     35 * The SMP lock implementation is architecture dependent.  The implementation
     36 * should provide fairness in case of concurrent lock attempts.  A ticket lock
     37 * is probably the most likely implementation.
     38 *
     39 * This SMP lock API has a flaw.  It does not provide the ability to use a
     40 * local context for acquire and release pairs.  Such a context is necessary to
     41 * implement for example the Mellor-Crummey and Scott (MCS) locks.  The SMP
     42 * lock is currently used in _Thread_Disable_dispatch() and
     43 * _Thread_Enable_dispatch() and makes them to a giant lock acquire and
     44 * release.  Since these functions do not pass state information via a local
     45 * context there is currently no use case for such a feature.
     46 *
     47 * @{
    4148 */
    42 typedef uint32_t SMP_lock_spinlock_simple_Control;
    4349
    4450/**
    45  *  This type is used to lock elements for atomic access.
    46  *  This spinlock supports nesting, but is slightly more
    47  *  complicated to use.  Please see the descriptions of
    48  *  obtain and release prior to using in order to understand
    49  *  the callers responsibilty of managing short interupt disable
    50  *  times.
     51 * @brief SMP lock control.
     52 *
     53 * This is an opaque type.  The SMP lock implementation is architecture
     54 * dependent.
    5155 */
    52 typedef struct {
    53   SMP_lock_spinlock_simple_Control lock;
    54   uint32_t  count;
    55   int       cpu_id;
    56 } SMP_lock_spinlock_nested_Control;
     56typedef CPU_SMP_lock_Control SMP_lock_Control;
    5757
    5858/**
    59  *  @brief Initialize a lock.
    60  *
    61  *  This method is used to initialize the lock at @a lock.
    62  *
    63  *  @param [in] lock is the address of the lock to obtain.
     59 * @brief SMP lock control initializer for static initialization.
    6460 */
    65 void _SMP_lock_spinlock_simple_Initialize(
    66   SMP_lock_spinlock_simple_Control *lock
    67 );
     61#define SMP_LOCK_INITIALIZER CPU_SMP_LOCK_INITIALIZER
    6862
    6963/**
    70  *  @brief Obtain a lock.
     64 * @brief Initializes a SMP lock control.
    7165 *
    72  *  This method is used to obtain the lock at @a lock.
     66 * Concurrent initialization leads to unpredictable results.
    7367 *
    74  *  @param [in] lock is the address of the lock to obtain.
    75  *
    76  *  @retval This method returns with processor interrupts disabled.
    77  *          The previous level is returned.
     68 * @param[out] lock The SMP lock control.
    7869 */
    79 ISR_Level _SMP_lock_spinlock_simple_Obtain(
    80   SMP_lock_spinlock_simple_Control *lock
    81 );
     70static inline void _SMP_lock_Initialize( SMP_lock_Control *lock )
     71{
     72  _CPU_SMP_lock_Initialize( lock );
     73}
    8274
    8375/**
    84  *  @brief Release a lock.
     76 * @brief Acquires a SMP lock.
    8577 *
    86  *  This method is used to release the lock at @a lock.
     78 * This function will not disable interrupts.  The caller must ensure that the
     79 * current thread of execution is not interrupted indefinite once it obtained
     80 * the SMP lock.
    8781 *
    88  *  @param [in] lock is the address of the lock to obtain.
     82 * @param[in/out] lock The SMP lock control.
    8983 */
    90 void _SMP_lock_spinlock_simple_Release(
    91   SMP_lock_spinlock_simple_Control  *lock,
    92   ISR_Level                         level
    93 );
     84static inline void _SMP_lock_Acquire( SMP_lock_Control *lock )
     85{
     86  _CPU_SMP_lock_Acquire( lock );
     87}
    9488
    9589/**
    96  *  @brief Initialize a lock.
     90 * @brief Releases a SMP lock.
    9791 *
    98  *  This method is used to initialize the lock at @a lock.
    99  *
    100  *  @param [in] lock is the address of the lock to obtain.
     92 * @param[in/out] lock The SMP lock control.
    10193 */
    102 void _SMP_lock_spinlock_nested_Initialize(
    103   SMP_lock_spinlock_nested_Control *lock
    104 );
     94static inline void _SMP_lock_Release( SMP_lock_Control *lock )
     95{
     96  _CPU_SMP_lock_Release( lock );
     97}
    10598
    10699/**
    107  *  @brief Obtain a lock.
     100 * @brief Disables interrupts and acquires the SMP lock.
    108101 *
    109  *  This method is used to obtain the lock at @a lock.  ISR's are
    110  *  disabled when this routine returns and it is the callers responsibility
    111  *  to either:
    112  *
    113  *   # Do something very short and then call
    114  *      _SMP_lock_spinlock_nested_Release  or
    115  *   # Do something very sort, call isr enable, then when ready
    116  *      call isr_disable and _SMP_lock_spinlock_nested_Release
    117  *
    118  *  @param [in] lock is the address of the lock to obtain.
    119  *
    120  *  @retval This method returns with processor interrupts disabled.
    121  *          The previous level is returned.
     102 * @param[in/out] lock The SMP lock control.
     103 * @param[out] isr_cookie The ISR cookie.
    122104 */
    123 ISR_Level _SMP_lock_spinlock_nested_Obtain(
    124   SMP_lock_spinlock_nested_Control *lock
    125 );
     105#define _SMP_lock_ISR_disable_and_acquire( lock, isr_cookie ) \
     106  _CPU_SMP_lock_ISR_disable_and_acquire( lock, isr_cookie )
    126107
    127108/**
    128  *  @brief Release a lock.
     109 * @brief Releases the SMP lock and enables interrupts.
    129110 *
    130  *  This method is used to release the lock at @a lock.
    131  *
    132  *  @note ISR's are reenabled by this method and are expected to be
    133  *  disabled upon entry to the method.
    134  *
    135  *  @param [in] lock is the address of the lock to obtain.
     111 * @param[in/out] lock The SMP lock control.
     112 * @param[in] isr_cookie The ISR cookie.
    136113 */
    137 void _SMP_lock_spinlock_nested_Release(
    138   SMP_lock_spinlock_nested_Control  *lock,
    139   ISR_Level                         level
    140 );
     114#define _SMP_lock_Release_and_ISR_enable( lock, isr_cookie ) \
     115  _CPU_SMP_lock_Release_and_ISR_enable( lock, isr_cookie )
     116
     117/**@}*/
    141118
    142119#ifdef __cplusplus
    143120}
    144 #endif
     121#endif /* __cplusplus */
    145122
    146 /**@}*/
    147 
    148 #endif
    149 /* end of include file */
     123#endif /* _RTEMS_SCORE_SMPLOCK_H */
  • cpukit/score/include/rtems/score/thread.h

    r7c5ceea5 re358088  
    471471
    472472#if defined(RTEMS_SMP)
     473  typedef struct {
     474    SMP_lock_Control lock;
     475    int owner_cpu;
     476    int nest_level;
     477  } Thread_Dispatch_disable_level_lock_control;
     478
    473479  /**
    474480   * The following declares the smp spinlock to be used to control
    475481   * the dispatch critical section accesses across cpus.
    476482   */
    477   SCORE_EXTERN SMP_lock_spinlock_nested_Control _Thread_Dispatch_disable_level_lock;
     483  SCORE_EXTERN Thread_Dispatch_disable_level_lock_control
     484    _Thread_Dispatch_disable_level_lock;
    478485#endif
    479486
  • cpukit/score/src/smp.c

    r7c5ceea5 re358088  
    7070
    7171
    72   level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
     72  _SMP_lock_ISR_disable_and_acquire( &per_cpu->lock, level );
    7373  message = per_cpu->message;
    7474  per_cpu->message = 0;
    75   _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
     75  _SMP_lock_Release_and_ISR_enable( &per_cpu->lock, level );
    7676
    7777  #if defined(RTEMS_DEBUG)
     
    116116  #endif
    117117
    118   level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
     118  _SMP_lock_ISR_disable_and_acquire( &per_cpu->lock, level );
    119119  per_cpu->message |= message;
    120   _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
     120  _SMP_lock_Release_and_ISR_enable( &per_cpu->lock, level );
    121121
    122122  bsp_smp_interrupt_cpu( cpu );
     
    132132    if ( cpu != self ) {
    133133      Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ];
    134       ISR_Level level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
     134      ISR_Level level;
     135
     136      _SMP_lock_ISR_disable_and_acquire( &per_cpu->lock, level );
    135137      per_cpu->message |= message;
    136       _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
     138      _SMP_lock_Release_and_ISR_enable( &per_cpu->lock, level );
    137139    }
    138140  }
  • cpukit/score/src/threaddispatchdisablelevel.c

    r7c5ceea5 re358088  
    2727#include <rtems/score/thread.h>
    2828
     29#define NO_OWNER_CPU (-1)
     30
    2931void _Thread_Dispatch_initialization( void )
    3032{
    31   _Thread_Dispatch_disable_level = 0;
    32   _SMP_lock_spinlock_nested_Initialize(&_Thread_Dispatch_disable_level_lock);
     33  Thread_Dispatch_disable_level_lock_control *level_lock =
     34    &_Thread_Dispatch_disable_level_lock;
     35
     36  _Thread_Dispatch_disable_level = 0;
     37  _SMP_lock_Initialize( &level_lock->lock );
     38  level_lock->owner_cpu = NO_OWNER_CPU;
    3339  _Thread_Dispatch_set_disable_level( 1 );
    3440}
     
    4753}
    4854
    49 uint32_t _Thread_Dispatch_increment_disable_level(void)
     55uint32_t _Thread_Dispatch_increment_disable_level( void )
    5056{
    51   ISR_Level  isr_level;
    52   uint32_t   level;
     57  Thread_Dispatch_disable_level_lock_control *level_lock =
     58    &_Thread_Dispatch_disable_level_lock;
     59  int self_cpu = bsp_smp_processor_id();
     60  ISR_Level isr_level;
     61  uint32_t disable_level;
    5362
    54   /*
    55    * Note: _SMP_lock_spinlock_nested_Obtain returns
    56    *       with ISR's disabled and the isr_level that
    57    *       should be restored after a short period.
    58    *
    59    * Here we obtain the lock and increment the
    60    * Thread dispatch disable level while under the
    61    * protection of the isr being off.  After this
    62    * point it is safe to re-enable ISRs and allow
    63    * the dispatch disable lock to provide protection.
    64    */
     63  _ISR_Disable_on_this_core( isr_level );
    6564
    66   isr_level = _SMP_lock_spinlock_nested_Obtain(
    67     &_Thread_Dispatch_disable_level_lock
    68   );
    69  
    70   _Thread_Dispatch_disable_level++;
    71   level = _Thread_Dispatch_disable_level;
     65  if ( level_lock->owner_cpu != self_cpu ) {
     66    _SMP_lock_Acquire( &level_lock->lock );
     67    level_lock->owner_cpu = self_cpu;
     68    level_lock->nest_level = 1;
     69  } else {
     70    ++level_lock->nest_level;
     71  }
    7272
    73   _ISR_Enable_on_this_core(isr_level);
    74   return level;
     73  disable_level = _Thread_Dispatch_disable_level;
     74  ++disable_level;
     75  _Thread_Dispatch_disable_level = disable_level;
     76
     77  _ISR_Enable_on_this_core( isr_level );
     78
     79  return disable_level;
    7580}
    7681
    77 uint32_t _Thread_Dispatch_decrement_disable_level(void)
     82uint32_t _Thread_Dispatch_decrement_disable_level( void )
    7883{
    79   ISR_Level  isr_level;
    80   uint32_t   level;
     84  Thread_Dispatch_disable_level_lock_control *level_lock =
     85    &_Thread_Dispatch_disable_level_lock;
     86  ISR_Level isr_level;
     87  uint32_t disable_level;
    8188
    82   /*  First we must disable ISRs in order to protect
    83    *  accesses to the dispatch disable level.
    84    */
    8589  _ISR_Disable_on_this_core( isr_level );
    8690
    87   _Thread_Dispatch_disable_level--;
    88   level = _Thread_Dispatch_disable_level;
     91  --level_lock->nest_level;
     92  if ( level_lock->nest_level == 0 ) {
     93    level_lock->owner_cpu = NO_OWNER_CPU;
     94    _SMP_lock_Release( &level_lock->lock );
     95  }
    8996
     97  disable_level = _Thread_Dispatch_disable_level;
     98  --disable_level;
     99  _Thread_Dispatch_disable_level = disable_level;
    90100
    91   /*
    92    * Note: _SMP_lock_spinlock_nested_Obtain returns with
    93    *        ISR's disabled and _SMP_lock_spinlock_nested_Release
    94    *        is responsable for re-enabling interrupts.
    95    */
    96   _SMP_lock_spinlock_nested_Release(
    97     &_Thread_Dispatch_disable_level_lock,
    98     isr_level
    99   );
     101  _ISR_Enable_on_this_core( isr_level );
    100102
    101   return level;
     103  return disable_level;
    102104}
    103105
Note: See TracChangeset for help on using the changeset viewer.