intl/icu/source/common/umutex.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/intl/icu/source/common/umutex.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,309 @@
     1.4 +/*
     1.5 +******************************************************************************
     1.6 +*
     1.7 +*   Copyright (C) 1997-2013, International Business Machines
     1.8 +*   Corporation and others.  All Rights Reserved.
     1.9 +*
    1.10 +******************************************************************************
    1.11 +*
    1.12 +* File umutex.cpp
    1.13 +*
    1.14 +* Modification History:
    1.15 +*
    1.16 +*   Date        Name        Description
    1.17 +*   04/02/97    aliu        Creation.
    1.18 +*   04/07/99    srl         updated
    1.19 +*   05/13/99    stephen     Changed to umutex (from cmutex).
    1.20 +*   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
    1.21 +******************************************************************************
    1.22 +*/
    1.23 +
    1.24 +#include "umutex.h"
    1.25 +
    1.26 +#include "unicode/utypes.h"
    1.27 +#include "uassert.h"
    1.28 +#include "cmemory.h"
    1.29 +#include "ucln_cmn.h"
    1.30 +
    1.31 +
    1.32 +// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
    1.33 +static UMutex   globalMutex = U_MUTEX_INITIALIZER;
    1.34 +
    1.35 +/*
    1.36 + * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
    1.37 + * platform independent set of mutex operations.  For internal ICU use only.
    1.38 + */
    1.39 +
    1.40 +#if defined(U_USER_MUTEX_CPP)
    1.41 +// Build time user mutex hook: #include "U_USER_MUTEX_CPP"
    1.42 +#include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
    1.43 +
    1.44 +#elif U_PLATFORM_HAS_WIN32_API
    1.45 +
    1.46 +//-------------------------------------------------------------------------------------------
    1.47 +//
    1.48 +//    Windows Specific Definitions
    1.49 +//
    1.50 +//        Note: Cygwin (and possibly others) have both WIN32 and POSIX.
    1.51 +//              Prefer Win32 in these cases.  (Win32 comes ahead in the #if chain)
    1.52 +//
    1.53 +//-------------------------------------------------------------------------------------------
    1.54 +
    1.55 +#if defined U_NO_PLATFORM_ATOMICS
    1.56 +#error ICU on Win32 requires support for low level atomic operations.
    1.57 +// Visual Studio, gcc, clang are OK. Shouldn't get here.
    1.58 +#endif
    1.59 +
    1.60 +
    1.61 +// This function is called when a test of a UInitOnce::fState reveals that
    1.62 +//   initialization has not completed, that we either need to call the
    1.63 +//   function on this thread, or wait for some other thread to complete.
    1.64 +//
    1.65 +// The actual call to the init function is made inline by template code
    1.66 +//   that knows the C++ types involved. This function returns TRUE if
    1.67 +//   the caller needs to call the Init function.
    1.68 +//
    1.69 +
    1.70 +U_NAMESPACE_BEGIN
    1.71 +
    1.72 +U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
    1.73 +    for (;;) {
    1.74 +        int32_t previousState = InterlockedCompareExchange(
    1.75 +#if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN)
    1.76 +           (LONG volatile *) // this is the type given in the API doc for this function.
    1.77 +#endif
    1.78 +            &uio.fState,  //  Destination
    1.79 +            1,            //  Exchange Value
    1.80 +            0);           //  Compare value
    1.81 +
    1.82 +        if (previousState == 0) {
    1.83 +            return true;   // Caller will next call the init function.
    1.84 +                           // Current state == 1.
    1.85 +        } else if (previousState == 2) {
    1.86 +            // Another thread already completed the initialization.
    1.87 +            //   We can simply return FALSE, indicating no
    1.88 +            //   further action is needed by the caller.
    1.89 +            return FALSE;
    1.90 +        } else {
    1.91 +            // Another thread is currently running the initialization.
    1.92 +            // Wait until it completes.
    1.93 +            do {
    1.94 +                Sleep(1);
    1.95 +                previousState = umtx_loadAcquire(uio.fState);
    1.96 +            } while (previousState == 1);
    1.97 +        }
    1.98 +    }
    1.99 +}
   1.100 +
   1.101 +// This function is called by the thread that ran an initialization function,
   1.102 +// just after completing the function.
   1.103 +//
   1.104 +//   success: True:  the inialization succeeded. No further calls to the init
   1.105 +//                   function will be made.
   1.106 +//            False: the initializtion failed. The next call to umtx_initOnce()
   1.107 +//                   will retry the initialization.
   1.108 +
   1.109 +U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
   1.110 +    umtx_storeRelease(uio.fState, 2);
   1.111 +}
   1.112 +
   1.113 +U_NAMESPACE_END
   1.114 +
   1.115 +static void winMutexInit(CRITICAL_SECTION *cs) {
   1.116 +    InitializeCriticalSection(cs);
   1.117 +    return;
   1.118 +}
   1.119 +
   1.120 +U_CAPI void  U_EXPORT2
   1.121 +umtx_lock(UMutex *mutex) {
   1.122 +    if (mutex == NULL) {
   1.123 +        mutex = &globalMutex;
   1.124 +    }
   1.125 +    CRITICAL_SECTION *cs = &mutex->fCS;
   1.126 +    umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
   1.127 +    EnterCriticalSection(cs);
   1.128 +}
   1.129 +
   1.130 +U_CAPI void  U_EXPORT2
   1.131 +umtx_unlock(UMutex* mutex)
   1.132 +{
   1.133 +    if (mutex == NULL) {
   1.134 +        mutex = &globalMutex;
   1.135 +    }
   1.136 +    LeaveCriticalSection(&mutex->fCS);
   1.137 +}
   1.138 +
   1.139 +#elif U_PLATFORM_IMPLEMENTS_POSIX
   1.140 +
   1.141 +//-------------------------------------------------------------------------------------------
   1.142 +//
   1.143 +//  POSIX specific definitions
   1.144 +//
   1.145 +//-------------------------------------------------------------------------------------------
   1.146 +
   1.147 +# include <pthread.h>
   1.148 +
   1.149 +// Each UMutex consists of a pthread_mutex_t.
   1.150 +// All are statically initialized and ready for use.
   1.151 +// There is no runtime mutex initialization code needed.
   1.152 +
   1.153 +U_CAPI void  U_EXPORT2
   1.154 +umtx_lock(UMutex *mutex) {
   1.155 +    if (mutex == NULL) {
   1.156 +        mutex = &globalMutex;
   1.157 +    }
   1.158 +    int sysErr = pthread_mutex_lock(&mutex->fMutex);
   1.159 +    (void)sysErr;   // Suppress unused variable warnings.
   1.160 +    U_ASSERT(sysErr == 0);
   1.161 +}
   1.162 +
   1.163 +
   1.164 +U_CAPI void  U_EXPORT2
   1.165 +umtx_unlock(UMutex* mutex)
   1.166 +{
   1.167 +    if (mutex == NULL) {
   1.168 +        mutex = &globalMutex;
   1.169 +    }
   1.170 +    int sysErr = pthread_mutex_unlock(&mutex->fMutex);
   1.171 +    (void)sysErr;   // Suppress unused variable warnings.
   1.172 +    U_ASSERT(sysErr == 0);
   1.173 +}
   1.174 +
   1.175 +U_NAMESPACE_BEGIN
   1.176 +
   1.177 +static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
   1.178 +static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
   1.179 +
   1.180 +
   1.181 +// This function is called when a test of a UInitOnce::fState reveals that
   1.182 +//   initialization has not completed, that we either need to call the
   1.183 +//   function on this thread, or wait for some other thread to complete.
   1.184 +//
   1.185 +// The actual call to the init function is made inline by template code
   1.186 +//   that knows the C++ types involved. This function returns TRUE if
   1.187 +//   the caller needs to call the Init function.
   1.188 +//
   1.189 +U_COMMON_API UBool U_EXPORT2
   1.190 +umtx_initImplPreInit(UInitOnce &uio) {
   1.191 +    pthread_mutex_lock(&initMutex);
   1.192 +    int32_t state = uio.fState;
   1.193 +    if (state == 0) {
   1.194 +        umtx_storeRelease(uio.fState, 1);
   1.195 +        pthread_mutex_unlock(&initMutex);
   1.196 +        return TRUE;   // Caller will next call the init function.
   1.197 +    } else {
   1.198 +        while (uio.fState == 1) {
   1.199 +            // Another thread is currently running the initialization.
   1.200 +            // Wait until it completes.
   1.201 +            pthread_cond_wait(&initCondition, &initMutex);
   1.202 +        }
   1.203 +        pthread_mutex_unlock(&initMutex);
   1.204 +        U_ASSERT(uio.fState == 2);
   1.205 +        return FALSE;
   1.206 +    }
   1.207 +}
   1.208 +
   1.209 +
   1.210 +
   1.211 +// This function is called by the thread that ran an initialization function,
   1.212 +// just after completing the function.
   1.213 +//   Some threads may be waiting on the condition, requiring the broadcast wakeup.
   1.214 +//   Some threads may be racing to test the fState variable outside of the mutex,
   1.215 +//   requiring the use of store/release when changing its value.
   1.216 +
   1.217 +U_COMMON_API void U_EXPORT2
   1.218 +umtx_initImplPostInit(UInitOnce &uio) {
   1.219 +    pthread_mutex_lock(&initMutex);
   1.220 +    umtx_storeRelease(uio.fState, 2);
   1.221 +    pthread_cond_broadcast(&initCondition);
   1.222 +    pthread_mutex_unlock(&initMutex);
   1.223 +}
   1.224 +
   1.225 +U_NAMESPACE_END
   1.226 +
   1.227 +// End of POSIX specific umutex implementation.
   1.228 +
   1.229 +#else  // Platform #define chain.
   1.230 +
   1.231 +#error Unknown Platform
   1.232 +
   1.233 +#endif  // Platform #define chain.
   1.234 +
   1.235 +
   1.236 +//-------------------------------------------------------------------------------
   1.237 +//
   1.238 +//   Atomic Operations, out-of-line versions.
   1.239 +//                      These are conditional, only defined if better versions
   1.240 +//                      were not available for the platform.
   1.241 +//
   1.242 +//                      These versions are platform neutral.
   1.243 +//
   1.244 +//--------------------------------------------------------------------------------
   1.245 +
   1.246 +#if defined U_NO_PLATFORM_ATOMICS
   1.247 +static UMutex   gIncDecMutex = U_MUTEX_INITIALIZER;
   1.248 +
   1.249 +U_NAMESPACE_BEGIN
   1.250 +
   1.251 +U_COMMON_API int32_t U_EXPORT2
   1.252 +umtx_atomic_inc(u_atomic_int32_t *p)  {
   1.253 +    int32_t retVal;
   1.254 +    umtx_lock(&gIncDecMutex);
   1.255 +    retVal = ++(*p);
   1.256 +    umtx_unlock(&gIncDecMutex);
   1.257 +    return retVal;
   1.258 +}
   1.259 +
   1.260 +
   1.261 +U_COMMON_API int32_t U_EXPORT2
   1.262 +umtx_atomic_dec(u_atomic_int32_t *p) {
   1.263 +    int32_t retVal;
   1.264 +    umtx_lock(&gIncDecMutex);
   1.265 +    retVal = --(*p);
   1.266 +    umtx_unlock(&gIncDecMutex);
   1.267 +    return retVal;
   1.268 +}
   1.269 +
   1.270 +U_COMMON_API int32_t U_EXPORT2
   1.271 +umtx_loadAcquire(u_atomic_int32_t &var) {
   1.272 +    int32_t val = var;
   1.273 +    umtx_lock(&gIncDecMutex);
   1.274 +    umtx_unlock(&gIncDecMutex);
   1.275 +    return val;
   1.276 +}
   1.277 +
   1.278 +U_COMMON_API void U_EXPORT2
   1.279 +umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
   1.280 +    umtx_lock(&gIncDecMutex);
   1.281 +    umtx_unlock(&gIncDecMutex);
   1.282 +    var = val;
   1.283 +}
   1.284 +
   1.285 +U_NAMESPACE_END
   1.286 +#endif
   1.287 +
   1.288 +//--------------------------------------------------------------------------
   1.289 +//
   1.290 +//  Deprecated functions for setting user mutexes.
   1.291 +//
   1.292 +//--------------------------------------------------------------------------
   1.293 +
   1.294 +U_DEPRECATED void U_EXPORT2
   1.295 +u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
   1.296 +                    UMtxFn *,  UMtxFn *, UErrorCode *status) {
   1.297 +    if (U_SUCCESS(*status)) {
   1.298 +        *status = U_UNSUPPORTED_ERROR;
   1.299 +    }
   1.300 +    return;
   1.301 +}
   1.302 +
   1.303 +
   1.304 +
   1.305 +U_DEPRECATED void U_EXPORT2
   1.306 +u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
   1.307 +                           UErrorCode *status) {
   1.308 +    if (U_SUCCESS(*status)) {
   1.309 +        *status = U_UNSUPPORTED_ERROR;
   1.310 +    }
   1.311 +    return;
   1.312 +}

mercurial