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 +}