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