1 /* 2 ********************************************************************** 3 * Copyright (C) 1997-2015, International Business Machines 4 * Corporation and others. All Rights Reserved. 5 ********************************************************************** 6 * 7 * File UMUTEX.H 8 * 9 * Modification History: 10 * 11 * Date Name Description 12 * 04/02/97 aliu Creation. 13 * 04/07/99 srl rewrite - C interface, multiple mutices 14 * 05/13/99 stephen Changed to umutex (from cmutex) 15 ****************************************************************************** 16 */ 17 18 #ifndef UMUTEX_H 19 #define UMUTEX_H 20 21 #include "unicode/utypes.h" 22 #include "unicode/uclean.h" 23 #include "putilimp.h" 24 25 26 27 // Forward Declarations. UMutex is not in the ICU namespace (yet) because 28 // there are some remaining references from plain C. 29 struct UMutex; 30 struct UConditionVar; 31 32 U_NAMESPACE_BEGIN 33 struct UInitOnce; 34 U_NAMESPACE_END 35 36 // Stringify macros, to allow #include of user supplied atomic & mutex files. 37 #define U_MUTEX_STR(s) #s 38 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s) 39 40 /**************************************************************************** 41 * 42 * Low Level Atomic Operations. 43 * Compiler dependent. Not operating system dependent. 44 * 45 ****************************************************************************/ 46 #if defined (U_USER_ATOMICS_H) 47 #include U_MUTEX_XSTR(U_USER_ATOMICS_H) 48 49 #elif U_HAVE_STD_ATOMICS 50 51 // C++11 atomics are available. 52 53 #include <atomic> 54 55 U_NAMESPACE_BEGIN 56 57 typedef std::atomic<int32_t> u_atomic_int32_t; 58 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val) 59 60 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 61 return var.load(std::memory_order_acquire); 62 } 63 64 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 65 var.store(val, std::memory_order_release); 66 } 67 68 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 69 return var->fetch_add(1) + 1; 70 } 71 72 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 73 return var->fetch_sub(1) - 1; 74 } 75 U_NAMESPACE_END 76 77 #elif U_PLATFORM_HAS_WIN32_API 78 79 // MSVC compiler. Reads and writes of volatile variables have 80 // acquire and release memory semantics, respectively. 81 // This is a Microsoft extension, not standard C++ behavior. 82 // 83 // Update: can't use this because of MinGW, built with gcc. 84 // Original plan was to use gcc atomics for MinGW, but they 85 // aren't supported, so we fold MinGW into this path. 86 87 # define WIN32_LEAN_AND_MEAN 88 # define VC_EXTRALEAN 89 # define NOUSER 90 # define NOSERVICE 91 # define NOIME 92 # define NOMCX 93 # ifndef NOMINMAX 94 # define NOMINMAX 95 # endif 96 # include <windows.h> 97 98 U_NAMESPACE_BEGIN 99 typedef volatile LONG u_atomic_int32_t; 100 #define ATOMIC_INT32_T_INITIALIZER(val) val 101 102 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 103 return InterlockedCompareExchange(&var, 0, 0); 104 } 105 106 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 107 InterlockedExchange(&var, val); 108 } 109 110 111 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 112 return InterlockedIncrement(var); 113 } 114 115 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 116 return InterlockedDecrement(var); 117 } 118 U_NAMESPACE_END 119 120 121 #elif U_HAVE_CLANG_ATOMICS 122 /* 123 * Clang __c11 atomic built-ins 124 */ 125 126 U_NAMESPACE_BEGIN 127 typedef _Atomic(int32_t) u_atomic_int32_t; 128 #define ATOMIC_INT32_T_INITIALIZER(val) val 129 130 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 131 return __c11_atomic_load(&var, __ATOMIC_ACQUIRE); 132 } 133 134 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 135 return __c11_atomic_store(&var, val, __ATOMIC_RELEASE); 136 } 137 138 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 139 return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1; 140 } 141 142 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 143 return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1; 144 } 145 U_NAMESPACE_END 146 147 148 #elif U_HAVE_GCC_ATOMICS 149 /* 150 * gcc atomic ops. These are available on several other compilers as well. 151 */ 152 153 U_NAMESPACE_BEGIN 154 typedef int32_t u_atomic_int32_t; 155 #define ATOMIC_INT32_T_INITIALIZER(val) val 156 157 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 158 int32_t val = var; 159 __sync_synchronize(); 160 return val; 161 } 162 163 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 164 __sync_synchronize(); 165 var = val; 166 } 167 168 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) { 169 return __sync_add_and_fetch(p, 1); 170 } 171 172 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) { 173 return __sync_sub_and_fetch(p, 1); 174 } 175 U_NAMESPACE_END 176 177 #else 178 179 /* 180 * Unknown Platform. Use out-of-line functions, which in turn use mutexes. 181 * Slow but correct. 182 */ 183 184 #define U_NO_PLATFORM_ATOMICS 185 186 U_NAMESPACE_BEGIN 187 typedef int32_t u_atomic_int32_t; 188 #define ATOMIC_INT32_T_INITIALIZER(val) val 189 190 U_COMMON_API int32_t U_EXPORT2 191 umtx_loadAcquire(u_atomic_int32_t &var); 192 193 U_COMMON_API void U_EXPORT2 194 umtx_storeRelease(u_atomic_int32_t &var, int32_t val); 195 196 U_COMMON_API int32_t U_EXPORT2 197 umtx_atomic_inc(u_atomic_int32_t *p); 198 199 U_COMMON_API int32_t U_EXPORT2 200 umtx_atomic_dec(u_atomic_int32_t *p); 201 202 U_NAMESPACE_END 203 204 #endif /* Low Level Atomic Ops Platfrom Chain */ 205 206 207 208 /************************************************************************************************* 209 * 210 * UInitOnce Definitions. 211 * These are platform neutral. 212 * 213 *************************************************************************************************/ 214 215 U_NAMESPACE_BEGIN 216 217 struct UInitOnce { 218 u_atomic_int32_t fState; 219 UErrorCode fErrCode; 220 void reset() {fState = 0;}; 221 UBool isReset() {return umtx_loadAcquire(fState) == 0;}; 222 // Note: isReset() is used by service registration code. 223 // Thread safety of this usage needs review. 224 }; 225 226 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR} 227 228 229 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &); 230 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &); 231 232 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) { 233 if (umtx_loadAcquire(uio.fState) == 2) { 234 return; 235 } 236 if (umtx_initImplPreInit(uio)) { 237 (obj->*fp)(); 238 umtx_initImplPostInit(uio); 239 } 240 } 241 242 243 // umtx_initOnce variant for plain functions, or static class functions. 244 // No context parameter. 245 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) { 246 if (umtx_loadAcquire(uio.fState) == 2) { 247 return; 248 } 249 if (umtx_initImplPreInit(uio)) { 250 (*fp)(); 251 umtx_initImplPostInit(uio); 252 } 253 } 254 255 // umtx_initOnce variant for plain functions, or static class functions. 256 // With ErrorCode, No context parameter. 257 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) { 258 if (U_FAILURE(errCode)) { 259 return; 260 } 261 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { 262 // We run the initialization. 263 (*fp)(errCode); 264 uio.fErrCode = errCode; 265 umtx_initImplPostInit(uio); 266 } else { 267 // Someone else already ran the initialization. 268 if (U_FAILURE(uio.fErrCode)) { 269 errCode = uio.fErrCode; 270 } 271 } 272 } 273 274 // umtx_initOnce variant for plain functions, or static class functions, 275 // with a context parameter. 276 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) { 277 if (umtx_loadAcquire(uio.fState) == 2) { 278 return; 279 } 280 if (umtx_initImplPreInit(uio)) { 281 (*fp)(context); 282 umtx_initImplPostInit(uio); 283 } 284 } 285 286 // umtx_initOnce variant for plain functions, or static class functions, 287 // with a context parameter and an error code. 288 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) { 289 if (U_FAILURE(errCode)) { 290 return; 291 } 292 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { 293 // We run the initialization. 294 (*fp)(context, errCode); 295 uio.fErrCode = errCode; 296 umtx_initImplPostInit(uio); 297 } else { 298 // Someone else already ran the initialization. 299 if (U_FAILURE(uio.fErrCode)) { 300 errCode = uio.fErrCode; 301 } 302 } 303 } 304 305 U_NAMESPACE_END 306 307 308 309 /************************************************************************************************* 310 * 311 * Mutex Definitions. Platform Dependent, #if platform chain follows. 312 * TODO: Add a C++11 version. 313 * Need to convert all mutex using files to C++ first. 314 * 315 *************************************************************************************************/ 316 317 #if defined(U_USER_MUTEX_H) 318 // #inlcude "U_USER_MUTEX_H" 319 #include U_MUTEX_XSTR(U_USER_MUTEX_H) 320 321 #elif U_PLATFORM_HAS_WIN32_API 322 323 /* Windows Definitions. 324 * Windows comes first in the platform chain. 325 * Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case. 326 */ 327 328 329 /* For CRITICAL_SECTION */ 330 331 /* 332 * Note: there is an earlier include of windows.h in this file, but it is in 333 * different conditionals. 334 * This one is needed if we are using C++11 for atomic ops, but 335 * win32 APIs for Critical Sections. 336 */ 337 338 # define WIN32_LEAN_AND_MEAN 339 # define VC_EXTRALEAN 340 # define NOUSER 341 # define NOSERVICE 342 # define NOIME 343 # define NOMCX 344 # ifndef NOMINMAX 345 # define NOMINMAX 346 # endif 347 # include <windows.h> 348 349 350 typedef struct UMutex { 351 icu::UInitOnce fInitOnce; 352 CRITICAL_SECTION fCS; 353 } UMutex; 354 355 /* Initializer for a static UMUTEX. Deliberately contains no value for the 356 * CRITICAL_SECTION. 357 */ 358 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER} 359 360 struct UConditionVar { 361 HANDLE fEntryGate; 362 HANDLE fExitGate; 363 int32_t fWaitCount; 364 }; 365 366 #define U_CONDITION_INITIALIZER {NULL, NULL, 0} 367 368 369 370 #elif U_PLATFORM_IMPLEMENTS_POSIX 371 372 /* 373 * POSIX platform 374 */ 375 376 #include <pthread.h> 377 378 struct UMutex { 379 pthread_mutex_t fMutex; 380 }; 381 typedef struct UMutex UMutex; 382 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER} 383 384 struct UConditionVar { 385 pthread_cond_t fCondition; 386 }; 387 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER} 388 389 #else 390 391 /* 392 * Unknow platform type. 393 * This is an error condition. ICU requires mutexes. 394 */ 395 396 #error Unknown Platform. 397 398 #endif 399 400 401 402 /************************************************************************************** 403 * 404 * Mutex Implementation function declaratations. 405 * Declarations are platform neutral. 406 * Implementations, in umutex.cpp, are platform specific. 407 * 408 ************************************************************************************/ 409 410 /* Lock a mutex. 411 * @param mutex The given mutex to be locked. Pass NULL to specify 412 * the global ICU mutex. Recursive locks are an error 413 * and may cause a deadlock on some platforms. 414 */ 415 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex); 416 417 /* Unlock a mutex. 418 * @param mutex The given mutex to be unlocked. Pass NULL to specify 419 * the global ICU mutex. 420 */ 421 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); 422 423 /* 424 * Wait on a condition variable. 425 * The calling thread will unlock the mutex and wait on the condition variable. 426 * The mutex must be locked by the calling thread when invoking this function. 427 * 428 * @param cond the condition variable to wait on. 429 * @param mutex the associated mutex. 430 */ 431 432 U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex); 433 434 435 /* 436 * Broadcast wakeup of all threads waiting on a Condition. 437 * The associated mutex must be locked by the calling thread when calling 438 * this function; this is a temporary ICU restriction. 439 * 440 * @param cond the condition variable. 441 */ 442 U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond); 443 444 /* 445 * Signal a condition variable, waking up one waiting thread. 446 * CAUTION: Do not use. Place holder only. Not implemented for Windows. 447 */ 448 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond); 449 450 #endif /* UMUTEX_H */ 451 /*eof*/ 452