1 /* 2 ********************************************************************** 3 * Copyright (C) 1997-2013, 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 31 U_NAMESPACE_BEGIN 32 struct UInitOnce; 33 U_NAMESPACE_END 34 35 // Stringify macros, to allow #include of user supplied atomic & mutex files. 36 #define U_MUTEX_STR(s) #s 37 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s) 38 39 /**************************************************************************** 40 * 41 * Low Level Atomic Operations. 42 * Compiler dependent. Not operating system dependent. 43 * 44 ****************************************************************************/ 45 #if defined (U_USER_ATOMICS_H) 46 #include U_MUTEX_XSTR(U_USER_ATOMICS_H) 47 48 #elif U_HAVE_STD_ATOMICS 49 50 // C++11 atomics are available. 51 52 #include <atomic> 53 54 U_NAMESPACE_BEGIN 55 56 typedef std::atomic<int32_t> u_atomic_int32_t; 57 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val) 58 59 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 60 return var.load(std::memory_order_acquire); 61 } 62 63 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 64 var.store(val, std::memory_order_release); 65 } 66 67 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 68 return var->fetch_add(1) + 1; 69 } 70 71 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 72 return var->fetch_sub(1) - 1; 73 } 74 U_NAMESPACE_END 75 76 #elif U_PLATFORM_HAS_WIN32_API 77 78 // MSVC compiler. Reads and writes of volatile variables have 79 // acquire and release memory semantics, respectively. 80 // This is a Microsoft extension, not standard C++ behavior. 81 // 82 // Update: can't use this because of MinGW, built with gcc. 83 // Original plan was to use gcc atomics for MinGW, but they 84 // aren't supported, so we fold MinGW into this path. 85 86 # define WIN32_LEAN_AND_MEAN 87 # define VC_EXTRALEAN 88 # define NOUSER 89 # define NOSERVICE 90 # define NOIME 91 # define NOMCX 92 # ifndef NOMINMAX 93 # define NOMINMAX 94 # endif 95 # include <windows.h> 96 97 U_NAMESPACE_BEGIN 98 typedef volatile LONG u_atomic_int32_t; 99 #define ATOMIC_INT32_T_INITIALIZER(val) val 100 101 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 102 return InterlockedCompareExchange(&var, 0, 0); 103 } 104 105 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 106 InterlockedExchange(&var, val); 107 } 108 109 110 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 111 return InterlockedIncrement(var); 112 } 113 114 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 115 return InterlockedDecrement(var); 116 } 117 U_NAMESPACE_END 118 119 120 #elif U_HAVE_GCC_ATOMICS 121 /* 122 * gcc atomic ops. These are available on several other compilers as well. 123 */ 124 125 U_NAMESPACE_BEGIN 126 typedef int32_t u_atomic_int32_t; 127 #define ATOMIC_INT32_T_INITIALIZER(val) val 128 129 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 130 int32_t val = var; 131 __sync_synchronize(); 132 return val; 133 } 134 135 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 136 __sync_synchronize(); 137 var = val; 138 } 139 140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) { 141 return __sync_add_and_fetch(p, 1); 142 } 143 144 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) { 145 return __sync_sub_and_fetch(p, 1); 146 } 147 U_NAMESPACE_END 148 149 #else 150 151 /* 152 * Unknown Platform. Use out-of-line functions, which in turn use mutexes. 153 * Slow but correct. 154 */ 155 156 #define U_NO_PLATFORM_ATOMICS 157 158 U_NAMESPACE_BEGIN 159 typedef int32_t u_atomic_int32_t; 160 #define ATOMIC_INT32_T_INITIALIZER(val) val 161 162 U_COMMON_API int32_t U_EXPORT2 163 umtx_loadAcquire(u_atomic_int32_t &var); 164 165 U_COMMON_API void U_EXPORT2 166 umtx_storeRelease(u_atomic_int32_t &var, int32_t val); 167 168 U_COMMON_API int32_t U_EXPORT2 169 umtx_atomic_inc(u_atomic_int32_t *p); 170 171 U_COMMON_API int32_t U_EXPORT2 172 umtx_atomic_dec(u_atomic_int32_t *p); 173 174 U_NAMESPACE_END 175 176 #endif /* Low Level Atomic Ops Platfrom Chain */ 177 178 179 180 /************************************************************************************************* 181 * 182 * UInitOnce Definitions. 183 * These are platform neutral. 184 * 185 *************************************************************************************************/ 186 187 U_NAMESPACE_BEGIN 188 189 struct UInitOnce { 190 u_atomic_int32_t fState; 191 UErrorCode fErrCode; 192 void reset() {fState = 0;}; 193 UBool isReset() {return umtx_loadAcquire(fState) == 0;}; 194 // Note: isReset() is used by service registration code. 195 // Thread safety of this usage needs review. 196 }; 197 198 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR} 199 200 201 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &); 202 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &); 203 204 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) { 205 if (umtx_loadAcquire(uio.fState) == 2) { 206 return; 207 } 208 if (umtx_initImplPreInit(uio)) { 209 (obj->*fp)(); 210 umtx_initImplPostInit(uio); 211 } 212 } 213 214 215 // umtx_initOnce variant for plain functions, or static class functions. 216 // No context parameter. 217 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) { 218 if (umtx_loadAcquire(uio.fState) == 2) { 219 return; 220 } 221 if (umtx_initImplPreInit(uio)) { 222 (*fp)(); 223 umtx_initImplPostInit(uio); 224 } 225 } 226 227 // umtx_initOnce variant for plain functions, or static class functions. 228 // With ErrorCode, No context parameter. 229 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) { 230 if (U_FAILURE(errCode)) { 231 return; 232 } 233 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { 234 // We run the initialization. 235 (*fp)(errCode); 236 uio.fErrCode = errCode; 237 umtx_initImplPostInit(uio); 238 } else { 239 // Someone else already ran the initialization. 240 if (U_FAILURE(uio.fErrCode)) { 241 errCode = uio.fErrCode; 242 } 243 } 244 } 245 246 // umtx_initOnce variant for plain functions, or static class functions, 247 // with a context parameter. 248 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) { 249 if (umtx_loadAcquire(uio.fState) == 2) { 250 return; 251 } 252 if (umtx_initImplPreInit(uio)) { 253 (*fp)(context); 254 umtx_initImplPostInit(uio); 255 } 256 } 257 258 // umtx_initOnce variant for plain functions, or static class functions, 259 // with a context parameter and an error code. 260 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) { 261 if (U_FAILURE(errCode)) { 262 return; 263 } 264 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { 265 // We run the initialization. 266 (*fp)(context, errCode); 267 uio.fErrCode = errCode; 268 umtx_initImplPostInit(uio); 269 } else { 270 // Someone else already ran the initialization. 271 if (U_FAILURE(uio.fErrCode)) { 272 errCode = uio.fErrCode; 273 } 274 } 275 } 276 277 U_NAMESPACE_END 278 279 280 281 /************************************************************************************************* 282 * 283 * Mutex Definitions. Platform Dependent, #if platform chain follows. 284 * TODO: Add a C++11 version. 285 * Need to convert all mutex using files to C++ first. 286 * 287 *************************************************************************************************/ 288 289 #if defined(U_USER_MUTEX_H) 290 // #inlcude "U_USER_MUTEX_H" 291 #include U_MUTEX_XSTR(U_USER_MUTEX_H) 292 293 #elif U_PLATFORM_HAS_WIN32_API 294 295 /* Windows Definitions. 296 * Windows comes first in the platform chain. 297 * Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case. 298 */ 299 300 301 /* For CRITICAL_SECTION */ 302 303 /* 304 * Note: there is an earlier include of windows.h in this file, but it is in 305 * different conditionals. 306 * This one is needed if we are using C++11 for atomic ops, but 307 * win32 APIs for Critical Sections. 308 */ 309 310 # define WIN32_LEAN_AND_MEAN 311 # define VC_EXTRALEAN 312 # define NOUSER 313 # define NOSERVICE 314 # define NOIME 315 # define NOMCX 316 # ifndef NOMINMAX 317 # define NOMINMAX 318 # endif 319 # include <windows.h> 320 321 322 typedef struct UMutex { 323 icu::UInitOnce fInitOnce; 324 CRITICAL_SECTION fCS; 325 } UMutex; 326 327 /* Initializer for a static UMUTEX. Deliberately contains no value for the 328 * CRITICAL_SECTION. 329 */ 330 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER} 331 332 333 334 #elif U_PLATFORM_IMPLEMENTS_POSIX 335 336 /* 337 * POSIX platform 338 */ 339 340 #include <pthread.h> 341 342 struct UMutex { 343 pthread_mutex_t fMutex; 344 }; 345 typedef struct UMutex UMutex; 346 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER} 347 348 #else 349 350 /* 351 * Unknow platform type. 352 * This is an error condition. ICU requires mutexes. 353 */ 354 355 #error Unknown Platform. 356 357 #endif 358 359 360 361 /************************************************************************************** 362 * 363 * Mutex Implementation function declaratations. 364 * Declarations are platform neutral. 365 * Implementations, in umutex.cpp, are platform specific. 366 * 367 ************************************************************************************/ 368 369 /* Lock a mutex. 370 * @param mutex The given mutex to be locked. Pass NULL to specify 371 * the global ICU mutex. Recursive locks are an error 372 * and may cause a deadlock on some platforms. 373 */ 374 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex); 375 376 /* Unlock a mutex. 377 * @param mutex The given mutex to be unlocked. Pass NULL to specify 378 * the global ICU mutex. 379 */ 380 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); 381 382 #endif /* UMUTEX_H */ 383 /*eof*/ 384