Home | History | Annotate | Download | only in common
      1 /*
      2 ******************************************************************************
      3 *
      4 *   Copyright (C) 1997-2015, International Business Machines
      5 *   Corporation and others.  All Rights Reserved.
      6 *
      7 ******************************************************************************
      8 *
      9 * File umutex.cpp
     10 *
     11 * Modification History:
     12 *
     13 *   Date        Name        Description
     14 *   04/02/97    aliu        Creation.
     15 *   04/07/99    srl         updated
     16 *   05/13/99    stephen     Changed to umutex (from cmutex).
     17 *   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
     18 ******************************************************************************
     19 */
     20 
     21 #include "umutex.h"
     22 
     23 #include "unicode/utypes.h"
     24 #include "uassert.h"
     25 #include "cmemory.h"
     26 
     27 
     28 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
     29 static UMutex   globalMutex = U_MUTEX_INITIALIZER;
     30 
     31 /*
     32  * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
     33  * platform independent set of mutex operations.  For internal ICU use only.
     34  */
     35 
     36 #if defined(U_USER_MUTEX_CPP)
     37 // Build time user mutex hook: #include "U_USER_MUTEX_CPP"
     38 #include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
     39 
     40 #elif U_PLATFORM_HAS_WIN32_API
     41 
     42 //-------------------------------------------------------------------------------------------
     43 //
     44 //    Windows Specific Definitions
     45 //
     46 //        Note: Cygwin (and possibly others) have both WIN32 and POSIX.
     47 //              Prefer Win32 in these cases.  (Win32 comes ahead in the #if chain)
     48 //
     49 //-------------------------------------------------------------------------------------------
     50 
     51 #if defined U_NO_PLATFORM_ATOMICS
     52 #error ICU on Win32 requires support for low level atomic operations.
     53 // Visual Studio, gcc, clang are OK. Shouldn't get here.
     54 #endif
     55 
     56 
     57 // This function is called when a test of a UInitOnce::fState reveals that
     58 //   initialization has not completed, that we either need to call the
     59 //   function on this thread, or wait for some other thread to complete.
     60 //
     61 // The actual call to the init function is made inline by template code
     62 //   that knows the C++ types involved. This function returns TRUE if
     63 //   the caller needs to call the Init function.
     64 //
     65 
     66 U_NAMESPACE_BEGIN
     67 
     68 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
     69     for (;;) {
     70         int32_t previousState = InterlockedCompareExchange(
     71 #if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN) || defined(__clang__)
     72            (LONG volatile *) // this is the type given in the API doc for this function.
     73 #endif
     74             &uio.fState,  //  Destination
     75             1,            //  Exchange Value
     76             0);           //  Compare value
     77 
     78         if (previousState == 0) {
     79             return true;   // Caller will next call the init function.
     80                            // Current state == 1.
     81         } else if (previousState == 2) {
     82             // Another thread already completed the initialization.
     83             //   We can simply return FALSE, indicating no
     84             //   further action is needed by the caller.
     85             return FALSE;
     86         } else {
     87             // Another thread is currently running the initialization.
     88             // Wait until it completes.
     89             do {
     90                 Sleep(1);
     91                 previousState = umtx_loadAcquire(uio.fState);
     92             } while (previousState == 1);
     93         }
     94     }
     95 }
     96 
     97 // This function is called by the thread that ran an initialization function,
     98 // just after completing the function.
     99 
    100 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
    101     umtx_storeRelease(uio.fState, 2);
    102 }
    103 
    104 U_NAMESPACE_END
    105 
    106 static void winMutexInit(CRITICAL_SECTION *cs) {
    107     InitializeCriticalSection(cs);
    108     return;
    109 }
    110 
    111 U_CAPI void  U_EXPORT2
    112 umtx_lock(UMutex *mutex) {
    113     if (mutex == NULL) {
    114         mutex = &globalMutex;
    115     }
    116     CRITICAL_SECTION *cs = &mutex->fCS;
    117     umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
    118     EnterCriticalSection(cs);
    119 }
    120 
    121 U_CAPI void  U_EXPORT2
    122 umtx_unlock(UMutex* mutex)
    123 {
    124     if (mutex == NULL) {
    125         mutex = &globalMutex;
    126     }
    127     LeaveCriticalSection(&mutex->fCS);
    128 }
    129 
    130 
    131 U_CAPI void U_EXPORT2
    132 umtx_condBroadcast(UConditionVar *condition) {
    133     // We require that the associated mutex be held by the caller,
    134     //  so access to fWaitCount is protected and safe. No other thread can
    135     //  call condWait() while we are here.
    136     if (condition->fWaitCount == 0) {
    137         return;
    138     }
    139     ResetEvent(condition->fExitGate);
    140     SetEvent(condition->fEntryGate);
    141 }
    142 
    143 U_CAPI void U_EXPORT2
    144 umtx_condSignal(UConditionVar *condition) {
    145     // Function not implemented. There is no immediate requirement from ICU to have it.
    146     // Once ICU drops support for Windows XP and Server 2003, ICU Condition Variables will be
    147     // changed to be thin wrappers on native Windows CONDITION_VARIABLEs, and this function
    148     // becomes trivial to provide.
    149     U_ASSERT(FALSE);
    150 }
    151 
    152 U_CAPI void U_EXPORT2
    153 umtx_condWait(UConditionVar *condition, UMutex *mutex) {
    154     if (condition->fEntryGate == NULL) {
    155         // Note: because the associated mutex must be locked when calling
    156         //       wait, we know that there can not be multiple threads
    157         //       running here with the same condition variable.
    158         //       Meaning that lazy initialization is safe.
    159         U_ASSERT(condition->fExitGate == NULL);
    160         condition->fEntryGate = CreateEvent(NULL,   // Security Attributes
    161                                             TRUE,   // Manual Reset
    162                                             FALSE,  // Initially reset
    163                                             NULL);  // Name.
    164         U_ASSERT(condition->fEntryGate != NULL);
    165         condition->fExitGate = CreateEvent(NULL, TRUE, TRUE, NULL);
    166         U_ASSERT(condition->fExitGate != NULL);
    167     }
    168 
    169     condition->fWaitCount++;
    170     umtx_unlock(mutex);
    171     WaitForSingleObject(condition->fEntryGate, INFINITE);
    172     umtx_lock(mutex);
    173     condition->fWaitCount--;
    174     if (condition->fWaitCount == 0) {
    175         // All threads that were waiting at the entry gate have woken up
    176         // and moved through. Shut the entry gate and open the exit gate.
    177         ResetEvent(condition->fEntryGate);
    178         SetEvent(condition->fExitGate);
    179     } else {
    180         umtx_unlock(mutex);
    181         WaitForSingleObject(condition->fExitGate, INFINITE);
    182         umtx_lock(mutex);
    183     }
    184 }
    185 
    186 
    187 #elif U_PLATFORM_IMPLEMENTS_POSIX
    188 
    189 //-------------------------------------------------------------------------------------------
    190 //
    191 //  POSIX specific definitions
    192 //
    193 //-------------------------------------------------------------------------------------------
    194 
    195 # include <pthread.h>
    196 
    197 // Each UMutex consists of a pthread_mutex_t.
    198 // All are statically initialized and ready for use.
    199 // There is no runtime mutex initialization code needed.
    200 
    201 U_CAPI void  U_EXPORT2
    202 umtx_lock(UMutex *mutex) {
    203     if (mutex == NULL) {
    204         mutex = &globalMutex;
    205     }
    206     int sysErr = pthread_mutex_lock(&mutex->fMutex);
    207     (void)sysErr;   // Suppress unused variable warnings.
    208     U_ASSERT(sysErr == 0);
    209 }
    210 
    211 
    212 U_CAPI void  U_EXPORT2
    213 umtx_unlock(UMutex* mutex)
    214 {
    215     if (mutex == NULL) {
    216         mutex = &globalMutex;
    217     }
    218     int sysErr = pthread_mutex_unlock(&mutex->fMutex);
    219     (void)sysErr;   // Suppress unused variable warnings.
    220     U_ASSERT(sysErr == 0);
    221 }
    222 
    223 
    224 U_CAPI void U_EXPORT2
    225 umtx_condWait(UConditionVar *cond, UMutex *mutex) {
    226     if (mutex == NULL) {
    227         mutex = &globalMutex;
    228     }
    229     int sysErr = pthread_cond_wait(&cond->fCondition, &mutex->fMutex);
    230     (void)sysErr;
    231     U_ASSERT(sysErr == 0);
    232 }
    233 
    234 U_CAPI void U_EXPORT2
    235 umtx_condBroadcast(UConditionVar *cond) {
    236     int sysErr = pthread_cond_broadcast(&cond->fCondition);
    237     (void)sysErr;
    238     U_ASSERT(sysErr == 0);
    239 }
    240 
    241 U_CAPI void U_EXPORT2
    242 umtx_condSignal(UConditionVar *cond) {
    243     int sysErr = pthread_cond_signal(&cond->fCondition);
    244     (void)sysErr;
    245     U_ASSERT(sysErr == 0);
    246 }
    247 
    248 
    249 
    250 U_NAMESPACE_BEGIN
    251 
    252 static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
    253 static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
    254 
    255 
    256 // This function is called when a test of a UInitOnce::fState reveals that
    257 //   initialization has not completed, that we either need to call the
    258 //   function on this thread, or wait for some other thread to complete.
    259 //
    260 // The actual call to the init function is made inline by template code
    261 //   that knows the C++ types involved. This function returns TRUE if
    262 //   the caller needs to call the Init function.
    263 //
    264 U_COMMON_API UBool U_EXPORT2
    265 umtx_initImplPreInit(UInitOnce &uio) {
    266     pthread_mutex_lock(&initMutex);
    267     int32_t state = uio.fState;
    268     if (state == 0) {
    269         umtx_storeRelease(uio.fState, 1);
    270         pthread_mutex_unlock(&initMutex);
    271         return TRUE;   // Caller will next call the init function.
    272     } else {
    273         while (uio.fState == 1) {
    274             // Another thread is currently running the initialization.
    275             // Wait until it completes.
    276             pthread_cond_wait(&initCondition, &initMutex);
    277         }
    278         pthread_mutex_unlock(&initMutex);
    279         U_ASSERT(uio.fState == 2);
    280         return FALSE;
    281     }
    282 }
    283 
    284 
    285 
    286 // This function is called by the thread that ran an initialization function,
    287 // just after completing the function.
    288 //   Some threads may be waiting on the condition, requiring the broadcast wakeup.
    289 //   Some threads may be racing to test the fState variable outside of the mutex,
    290 //   requiring the use of store/release when changing its value.
    291 
    292 U_COMMON_API void U_EXPORT2
    293 umtx_initImplPostInit(UInitOnce &uio) {
    294     pthread_mutex_lock(&initMutex);
    295     umtx_storeRelease(uio.fState, 2);
    296     pthread_cond_broadcast(&initCondition);
    297     pthread_mutex_unlock(&initMutex);
    298 }
    299 
    300 U_NAMESPACE_END
    301 
    302 // End of POSIX specific umutex implementation.
    303 
    304 #else  // Platform #define chain.
    305 
    306 #error Unknown Platform
    307 
    308 #endif  // Platform #define chain.
    309 
    310 
    311 //-------------------------------------------------------------------------------
    312 //
    313 //   Atomic Operations, out-of-line versions.
    314 //                      These are conditional, only defined if better versions
    315 //                      were not available for the platform.
    316 //
    317 //                      These versions are platform neutral.
    318 //
    319 //--------------------------------------------------------------------------------
    320 
    321 #if defined U_NO_PLATFORM_ATOMICS
    322 static UMutex   gIncDecMutex = U_MUTEX_INITIALIZER;
    323 
    324 U_NAMESPACE_BEGIN
    325 
    326 U_COMMON_API int32_t U_EXPORT2
    327 umtx_atomic_inc(u_atomic_int32_t *p)  {
    328     int32_t retVal;
    329     umtx_lock(&gIncDecMutex);
    330     retVal = ++(*p);
    331     umtx_unlock(&gIncDecMutex);
    332     return retVal;
    333 }
    334 
    335 
    336 U_COMMON_API int32_t U_EXPORT2
    337 umtx_atomic_dec(u_atomic_int32_t *p) {
    338     int32_t retVal;
    339     umtx_lock(&gIncDecMutex);
    340     retVal = --(*p);
    341     umtx_unlock(&gIncDecMutex);
    342     return retVal;
    343 }
    344 
    345 U_COMMON_API int32_t U_EXPORT2
    346 umtx_loadAcquire(u_atomic_int32_t &var) {
    347     umtx_lock(&gIncDecMutex);
    348     int32_t val = var;
    349     umtx_unlock(&gIncDecMutex);
    350     return val;
    351 }
    352 
    353 U_COMMON_API void U_EXPORT2
    354 umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    355     umtx_lock(&gIncDecMutex);
    356     var = val;
    357     umtx_unlock(&gIncDecMutex);
    358 }
    359 
    360 U_NAMESPACE_END
    361 #endif
    362 
    363 //--------------------------------------------------------------------------
    364 //
    365 //  Deprecated functions for setting user mutexes.
    366 //
    367 //--------------------------------------------------------------------------
    368 
    369 U_DEPRECATED void U_EXPORT2
    370 u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
    371                     UMtxFn *,  UMtxFn *, UErrorCode *status) {
    372     if (U_SUCCESS(*status)) {
    373         *status = U_UNSUPPORTED_ERROR;
    374     }
    375     return;
    376 }
    377 
    378 
    379 
    380 U_DEPRECATED void U_EXPORT2
    381 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
    382                            UErrorCode *status) {
    383     if (U_SUCCESS(*status)) {
    384         *status = U_UNSUPPORTED_ERROR;
    385     }
    386     return;
    387 }
    388