LCOV - code coverage report
Current view: top level - intl/icu/source/common - umutex.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 25 52 48.1 %
Date: 2017-07-14 16:53:18 Functions: 4 9 44.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13