intl/icu/source/common/umutex.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

     1 /*
     2 ******************************************************************************
     3 *
     4 *   Copyright (C) 1997-2013, 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 */
    21 #include "umutex.h"
    23 #include "unicode/utypes.h"
    24 #include "uassert.h"
    25 #include "cmemory.h"
    26 #include "ucln_cmn.h"
    29 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
    30 static UMutex   globalMutex = U_MUTEX_INITIALIZER;
    32 /*
    33  * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
    34  * platform independent set of mutex operations.  For internal ICU use only.
    35  */
    37 #if defined(U_USER_MUTEX_CPP)
    38 // Build time user mutex hook: #include "U_USER_MUTEX_CPP"
    39 #include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
    41 #elif U_PLATFORM_HAS_WIN32_API
    43 //-------------------------------------------------------------------------------------------
    44 //
    45 //    Windows Specific Definitions
    46 //
    47 //        Note: Cygwin (and possibly others) have both WIN32 and POSIX.
    48 //              Prefer Win32 in these cases.  (Win32 comes ahead in the #if chain)
    49 //
    50 //-------------------------------------------------------------------------------------------
    52 #if defined U_NO_PLATFORM_ATOMICS
    53 #error ICU on Win32 requires support for low level atomic operations.
    54 // Visual Studio, gcc, clang are OK. Shouldn't get here.
    55 #endif
    58 // This function is called when a test of a UInitOnce::fState reveals that
    59 //   initialization has not completed, that we either need to call the
    60 //   function on this thread, or wait for some other thread to complete.
    61 //
    62 // The actual call to the init function is made inline by template code
    63 //   that knows the C++ types involved. This function returns TRUE if
    64 //   the caller needs to call the Init function.
    65 //
    67 U_NAMESPACE_BEGIN
    69 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
    70     for (;;) {
    71         int32_t previousState = InterlockedCompareExchange(
    72 #if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN)
    73            (LONG volatile *) // this is the type given in the API doc for this function.
    74 #endif
    75             &uio.fState,  //  Destination
    76             1,            //  Exchange Value
    77             0);           //  Compare value
    79         if (previousState == 0) {
    80             return true;   // Caller will next call the init function.
    81                            // Current state == 1.
    82         } else if (previousState == 2) {
    83             // Another thread already completed the initialization.
    84             //   We can simply return FALSE, indicating no
    85             //   further action is needed by the caller.
    86             return FALSE;
    87         } else {
    88             // Another thread is currently running the initialization.
    89             // Wait until it completes.
    90             do {
    91                 Sleep(1);
    92                 previousState = umtx_loadAcquire(uio.fState);
    93             } while (previousState == 1);
    94         }
    95     }
    96 }
    98 // This function is called by the thread that ran an initialization function,
    99 // just after completing the function.
   100 //
   101 //   success: True:  the inialization succeeded. No further calls to the init
   102 //                   function will be made.
   103 //            False: the initializtion failed. The next call to umtx_initOnce()
   104 //                   will retry the initialization.
   106 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
   107     umtx_storeRelease(uio.fState, 2);
   108 }
   110 U_NAMESPACE_END
   112 static void winMutexInit(CRITICAL_SECTION *cs) {
   113     InitializeCriticalSection(cs);
   114     return;
   115 }
   117 U_CAPI void  U_EXPORT2
   118 umtx_lock(UMutex *mutex) {
   119     if (mutex == NULL) {
   120         mutex = &globalMutex;
   121     }
   122     CRITICAL_SECTION *cs = &mutex->fCS;
   123     umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
   124     EnterCriticalSection(cs);
   125 }
   127 U_CAPI void  U_EXPORT2
   128 umtx_unlock(UMutex* mutex)
   129 {
   130     if (mutex == NULL) {
   131         mutex = &globalMutex;
   132     }
   133     LeaveCriticalSection(&mutex->fCS);
   134 }
   136 #elif U_PLATFORM_IMPLEMENTS_POSIX
   138 //-------------------------------------------------------------------------------------------
   139 //
   140 //  POSIX specific definitions
   141 //
   142 //-------------------------------------------------------------------------------------------
   144 # include <pthread.h>
   146 // Each UMutex consists of a pthread_mutex_t.
   147 // All are statically initialized and ready for use.
   148 // There is no runtime mutex initialization code needed.
   150 U_CAPI void  U_EXPORT2
   151 umtx_lock(UMutex *mutex) {
   152     if (mutex == NULL) {
   153         mutex = &globalMutex;
   154     }
   155     int sysErr = pthread_mutex_lock(&mutex->fMutex);
   156     (void)sysErr;   // Suppress unused variable warnings.
   157     U_ASSERT(sysErr == 0);
   158 }
   161 U_CAPI void  U_EXPORT2
   162 umtx_unlock(UMutex* mutex)
   163 {
   164     if (mutex == NULL) {
   165         mutex = &globalMutex;
   166     }
   167     int sysErr = pthread_mutex_unlock(&mutex->fMutex);
   168     (void)sysErr;   // Suppress unused variable warnings.
   169     U_ASSERT(sysErr == 0);
   170 }
   172 U_NAMESPACE_BEGIN
   174 static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
   175 static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
   178 // This function is called when a test of a UInitOnce::fState reveals that
   179 //   initialization has not completed, that we either need to call the
   180 //   function on this thread, or wait for some other thread to complete.
   181 //
   182 // The actual call to the init function is made inline by template code
   183 //   that knows the C++ types involved. This function returns TRUE if
   184 //   the caller needs to call the Init function.
   185 //
   186 U_COMMON_API UBool U_EXPORT2
   187 umtx_initImplPreInit(UInitOnce &uio) {
   188     pthread_mutex_lock(&initMutex);
   189     int32_t state = uio.fState;
   190     if (state == 0) {
   191         umtx_storeRelease(uio.fState, 1);
   192         pthread_mutex_unlock(&initMutex);
   193         return TRUE;   // Caller will next call the init function.
   194     } else {
   195         while (uio.fState == 1) {
   196             // Another thread is currently running the initialization.
   197             // Wait until it completes.
   198             pthread_cond_wait(&initCondition, &initMutex);
   199         }
   200         pthread_mutex_unlock(&initMutex);
   201         U_ASSERT(uio.fState == 2);
   202         return FALSE;
   203     }
   204 }
   208 // This function is called by the thread that ran an initialization function,
   209 // just after completing the function.
   210 //   Some threads may be waiting on the condition, requiring the broadcast wakeup.
   211 //   Some threads may be racing to test the fState variable outside of the mutex,
   212 //   requiring the use of store/release when changing its value.
   214 U_COMMON_API void U_EXPORT2
   215 umtx_initImplPostInit(UInitOnce &uio) {
   216     pthread_mutex_lock(&initMutex);
   217     umtx_storeRelease(uio.fState, 2);
   218     pthread_cond_broadcast(&initCondition);
   219     pthread_mutex_unlock(&initMutex);
   220 }
   222 U_NAMESPACE_END
   224 // End of POSIX specific umutex implementation.
   226 #else  // Platform #define chain.
   228 #error Unknown Platform
   230 #endif  // Platform #define chain.
   233 //-------------------------------------------------------------------------------
   234 //
   235 //   Atomic Operations, out-of-line versions.
   236 //                      These are conditional, only defined if better versions
   237 //                      were not available for the platform.
   238 //
   239 //                      These versions are platform neutral.
   240 //
   241 //--------------------------------------------------------------------------------
   243 #if defined U_NO_PLATFORM_ATOMICS
   244 static UMutex   gIncDecMutex = U_MUTEX_INITIALIZER;
   246 U_NAMESPACE_BEGIN
   248 U_COMMON_API int32_t U_EXPORT2
   249 umtx_atomic_inc(u_atomic_int32_t *p)  {
   250     int32_t retVal;
   251     umtx_lock(&gIncDecMutex);
   252     retVal = ++(*p);
   253     umtx_unlock(&gIncDecMutex);
   254     return retVal;
   255 }
   258 U_COMMON_API int32_t U_EXPORT2
   259 umtx_atomic_dec(u_atomic_int32_t *p) {
   260     int32_t retVal;
   261     umtx_lock(&gIncDecMutex);
   262     retVal = --(*p);
   263     umtx_unlock(&gIncDecMutex);
   264     return retVal;
   265 }
   267 U_COMMON_API int32_t U_EXPORT2
   268 umtx_loadAcquire(u_atomic_int32_t &var) {
   269     int32_t val = var;
   270     umtx_lock(&gIncDecMutex);
   271     umtx_unlock(&gIncDecMutex);
   272     return val;
   273 }
   275 U_COMMON_API void U_EXPORT2
   276 umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
   277     umtx_lock(&gIncDecMutex);
   278     umtx_unlock(&gIncDecMutex);
   279     var = val;
   280 }
   282 U_NAMESPACE_END
   283 #endif
   285 //--------------------------------------------------------------------------
   286 //
   287 //  Deprecated functions for setting user mutexes.
   288 //
   289 //--------------------------------------------------------------------------
   291 U_DEPRECATED void U_EXPORT2
   292 u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
   293                     UMtxFn *,  UMtxFn *, UErrorCode *status) {
   294     if (U_SUCCESS(*status)) {
   295         *status = U_UNSUPPORTED_ERROR;
   296     }
   297     return;
   298 }
   302 U_DEPRECATED void U_EXPORT2
   303 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
   304                            UErrorCode *status) {
   305     if (U_SUCCESS(*status)) {
   306         *status = U_UNSUPPORTED_ERROR;
   307     }
   308     return;
   309 }

mercurial