Home | History | Annotate | Download | only in BaseLib
      1 /**
      2   Implementation of synchronization functions.
      3 
      4   Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13   Module Name:  SynchronizationMsc.c
     14 
     15 **/
     16 
     17 #include "BaseLibInternals.h"
     18 
     19 //
     20 // Microsoft Visual Studio 7.1 Function Prototypes for read write barrier Intrinsics
     21 //
     22 void    _ReadWriteBarrier (void);
     23 #pragma intrinsic(_ReadWriteBarrier)
     24 
     25 
     26 #define SPIN_LOCK_RELEASED          ((UINTN) 1)
     27 #define SPIN_LOCK_ACQUIRED          ((UINTN) 2)
     28 
     29 /**
     30   Retrieves the architecture specific spin lock alignment requirements for
     31   optimal spin lock performance.
     32 
     33   This function retrieves the spin lock alignment requirements for optimal
     34   performance on a given CPU architecture. The spin lock alignment must be a
     35   power of two and is returned by this function. If there are no alignment
     36   requirements, then 1 must be returned. The spin lock synchronization
     37   functions must function correctly if the spin lock size and alignment values
     38   returned by this function are not used at all. These values are hints to the
     39   consumers of the spin lock synchronization functions to obtain optimal spin
     40   lock performance.
     41 
     42   @return The architecture specific spin lock alignment.
     43 
     44 **/
     45 UINTN
     46 EFIAPI
     47 GetSpinLockProperties (
     48   VOID
     49   )
     50 {
     51   // @bug May use a PCD entry to determine this alignment.
     52   return 32;
     53 }
     54 
     55 /**
     56   Initializes a spin lock to the released state and returns the spin lock.
     57 
     58   This function initializes the spin lock specified by SpinLock to the released
     59   state, and returns SpinLock. Optimal performance can be achieved by calling
     60   GetSpinLockProperties() to determine the size and alignment requirements for
     61   SpinLock.
     62 
     63   If SpinLock is NULL, then ASSERT().
     64 
     65   @param  SpinLock  A pointer to the spin lock to initialize to the released
     66                     state.
     67 
     68   @return SpinLock
     69 
     70 **/
     71 SPIN_LOCK *
     72 EFIAPI
     73 InitializeSpinLock (
     74   OUT     SPIN_LOCK                 *SpinLock
     75   )
     76 {
     77   ASSERT (SpinLock != NULL);
     78 
     79   _ReadWriteBarrier();
     80   *SpinLock = SPIN_LOCK_RELEASED;
     81   _ReadWriteBarrier();
     82 
     83   return SpinLock;
     84 }
     85 
     86 /**
     87   Waits until a spin lock can be placed in the acquired state.
     88 
     89   This function checks the state of the spin lock specified by SpinLock. If
     90   SpinLock is in the released state, then this function places SpinLock in the
     91   acquired state and returns SpinLock. Otherwise, this function waits
     92   indefinitely for the spin lock to be released, and then places it in the
     93   acquired state and returns SpinLock. All state transitions of SpinLock must
     94   be performed using MP safe mechanisms.
     95 
     96   If SpinLock is NULL, then ASSERT().
     97   If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
     98   If PcdSpinLockTimeout is not zero, and SpinLock is can not be acquired in
     99   PcdSpinLockTimeout microseconds, then ASSERT().
    100 
    101   @param  SpinLock  A pointer to the spin lock to place in the acquired state.
    102 
    103   @return SpinLock
    104 
    105 **/
    106 SPIN_LOCK *
    107 EFIAPI
    108 AcquireSpinLock (
    109   IN OUT  SPIN_LOCK                 *SpinLock
    110   )
    111 {
    112   UINT64                            Tick;
    113   UINT64                            Start, End;
    114   UINT64                            Timeout;
    115 
    116   Tick = 0;
    117   Start = 0;
    118   End = 0;
    119   if (PcdGet32 (PcdSpinLockTimeout) > 0) {
    120     Tick = GetPerformanceCounter ();
    121     Timeout = DivU64x32 (
    122                 MultU64x32 (
    123                   GetPerformanceCounterProperties (&Start, &End),
    124                   PcdGet32 (PcdSpinLockTimeout)
    125                   ),
    126                 1000000
    127                 );
    128     if (Start < End) {
    129       Tick += Timeout;
    130     } else {
    131       Tick -= Timeout;
    132     }
    133   }
    134 
    135   while (!AcquireSpinLockOrFail (SpinLock)) {
    136     CpuPause ();
    137     ASSERT ((Start < End) ^ (Tick <= GetPerformanceCounter ()));
    138   }
    139   return SpinLock;
    140 }
    141 
    142 /**
    143   Attempts to place a spin lock in the acquired state.
    144 
    145   This function checks the state of the spin lock specified by SpinLock. If
    146   SpinLock is in the released state, then this function places SpinLock in the
    147   acquired state and returns TRUE. Otherwise, FALSE is returned. All state
    148   transitions of SpinLock must be performed using MP safe mechanisms.
    149 
    150   If SpinLock is NULL, then ASSERT().
    151   If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
    152 
    153   @param  SpinLock  A pointer to the spin lock to place in the acquired state.
    154 
    155   @retval TRUE  SpinLock was placed in the acquired state.
    156   @retval FALSE SpinLock could not be acquired.
    157 
    158 **/
    159 BOOLEAN
    160 EFIAPI
    161 AcquireSpinLockOrFail (
    162   IN OUT  SPIN_LOCK                 *SpinLock
    163   )
    164 {
    165   SPIN_LOCK   LockValue;
    166   VOID        *Result;
    167 
    168   ASSERT (SpinLock != NULL);
    169 
    170   LockValue = *SpinLock;
    171   ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
    172 
    173   _ReadWriteBarrier ();
    174   Result = InterlockedCompareExchangePointer (
    175              (VOID**)SpinLock,
    176              (VOID*)SPIN_LOCK_RELEASED,
    177              (VOID*)SPIN_LOCK_ACQUIRED
    178            );
    179 
    180   _ReadWriteBarrier ();
    181   return (BOOLEAN) (Result == (VOID*) SPIN_LOCK_RELEASED);
    182 }
    183 
    184 /**
    185   Releases a spin lock.
    186 
    187   This function places the spin lock specified by SpinLock in the release state
    188   and returns SpinLock.
    189 
    190   If SpinLock is NULL, then ASSERT().
    191   If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
    192 
    193   @param  SpinLock  A pointer to the spin lock to release.
    194 
    195   @return SpinLock
    196 
    197 **/
    198 SPIN_LOCK *
    199 EFIAPI
    200 ReleaseSpinLock (
    201   IN OUT  SPIN_LOCK                 *SpinLock
    202   )
    203 {
    204   SPIN_LOCK    LockValue;
    205 
    206   ASSERT (SpinLock != NULL);
    207 
    208   LockValue = *SpinLock;
    209   ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
    210 
    211   _ReadWriteBarrier ();
    212   *SpinLock = SPIN_LOCK_RELEASED;
    213   _ReadWriteBarrier ();
    214 
    215   return SpinLock;
    216 }
    217 
    218 /**
    219   Performs an atomic increment of an 32-bit unsigned integer.
    220 
    221   Performs an atomic increment of the 32-bit unsigned integer specified by
    222   Value and returns the incremented value. The increment operation must be
    223   performed using MP safe mechanisms. The state of the return value is not
    224   guaranteed to be MP safe.
    225 
    226   If Value is NULL, then ASSERT().
    227 
    228   @param  Value A pointer to the 32-bit value to increment.
    229 
    230   @return The incremented value.
    231 
    232 **/
    233 UINT32
    234 EFIAPI
    235 InterlockedIncrement (
    236   IN      UINT32                    *Value
    237   )
    238 {
    239   ASSERT (Value != NULL);
    240   return InternalSyncIncrement (Value);
    241 }
    242 
    243 /**
    244   Performs an atomic decrement of an 32-bit unsigned integer.
    245 
    246   Performs an atomic decrement of the 32-bit unsigned integer specified by
    247   Value and returns the decremented value. The decrement operation must be
    248   performed using MP safe mechanisms. The state of the return value is not
    249   guaranteed to be MP safe.
    250 
    251   If Value is NULL, then ASSERT().
    252 
    253   @param  Value A pointer to the 32-bit value to decrement.
    254 
    255   @return The decremented value.
    256 
    257 **/
    258 UINT32
    259 EFIAPI
    260 InterlockedDecrement (
    261   IN      UINT32                    *Value
    262   )
    263 {
    264   ASSERT (Value != NULL);
    265   return InternalSyncDecrement (Value);
    266 }
    267 
    268 /**
    269   Performs an atomic compare exchange operation on a 32-bit unsigned integer.
    270 
    271   Performs an atomic compare exchange operation on the 32-bit unsigned integer
    272   specified by Value.  If Value is equal to CompareValue, then Value is set to
    273   ExchangeValue and CompareValue is returned.  If Value is not equal to CompareValue,
    274   then Value is returned.  The compare exchange operation must be performed using
    275   MP safe mechanisms.
    276 
    277   If Value is NULL, then ASSERT().
    278 
    279   @param  Value         A pointer to the 32-bit value for the compare exchange
    280                         operation.
    281   @param  CompareValue  32-bit value used in compare operation.
    282   @param  ExchangeValue 32-bit value used in exchange operation.
    283 
    284   @return The original *Value before exchange.
    285 
    286 **/
    287 UINT32
    288 EFIAPI
    289 InterlockedCompareExchange32 (
    290   IN OUT  UINT32                    *Value,
    291   IN      UINT32                    CompareValue,
    292   IN      UINT32                    ExchangeValue
    293   )
    294 {
    295   ASSERT (Value != NULL);
    296   return InternalSyncCompareExchange32 (Value, CompareValue, ExchangeValue);
    297 }
    298 
    299 /**
    300   Performs an atomic compare exchange operation on a 64-bit unsigned integer.
    301 
    302   Performs an atomic compare exchange operation on the 64-bit unsigned integer specified
    303   by Value.  If Value is equal to CompareValue, then Value is set to ExchangeValue and
    304   CompareValue is returned.  If Value is not equal to CompareValue, then Value is returned.
    305   The compare exchange operation must be performed using MP safe mechanisms.
    306 
    307   If Value is NULL, then ASSERT().
    308 
    309   @param  Value         A pointer to the 64-bit value for the compare exchange
    310                         operation.
    311   @param  CompareValue  64-bit value used in compare operation.
    312   @param  ExchangeValue 64-bit value used in exchange operation.
    313 
    314   @return The original *Value before exchange.
    315 
    316 **/
    317 UINT64
    318 EFIAPI
    319 InterlockedCompareExchange64 (
    320   IN OUT  UINT64                    *Value,
    321   IN      UINT64                    CompareValue,
    322   IN      UINT64                    ExchangeValue
    323   )
    324 {
    325   ASSERT (Value != NULL);
    326   return InternalSyncCompareExchange64 (Value, CompareValue, ExchangeValue);
    327 }
    328 
    329 /**
    330   Performs an atomic compare exchange operation on a pointer value.
    331 
    332   Performs an atomic compare exchange operation on the pointer value specified
    333   by Value. If Value is equal to CompareValue, then Value is set to
    334   ExchangeValue and CompareValue is returned. If Value is not equal to
    335   CompareValue, then Value is returned. The compare exchange operation must be
    336   performed using MP safe mechanisms.
    337 
    338   If Value is NULL, then ASSERT().
    339 
    340   @param  Value         A pointer to the pointer value for the compare exchange
    341                         operation.
    342   @param  CompareValue  Pointer value used in compare operation.
    343   @param  ExchangeValue Pointer value used in exchange operation.
    344 
    345 **/
    346 VOID *
    347 EFIAPI
    348 InterlockedCompareExchangePointer (
    349   IN OUT  VOID                      **Value,
    350   IN      VOID                      *CompareValue,
    351   IN      VOID                      *ExchangeValue
    352   )
    353 {
    354   UINT8  SizeOfValue;
    355 
    356   SizeOfValue = (UINT8) sizeof (*Value);
    357 
    358   switch (SizeOfValue) {
    359     case sizeof (UINT32):
    360       return (VOID*)(UINTN)InterlockedCompareExchange32 (
    361                              (UINT32*)Value,
    362                              (UINT32)(UINTN)CompareValue,
    363                              (UINT32)(UINTN)ExchangeValue
    364                              );
    365     case sizeof (UINT64):
    366       return (VOID*)(UINTN)InterlockedCompareExchange64 (
    367                              (UINT64*)Value,
    368                              (UINT64)(UINTN)CompareValue,
    369                              (UINT64)(UINTN)ExchangeValue
    370                              );
    371     default:
    372       ASSERT (FALSE);
    373       return NULL;
    374   }
    375 }
    376