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