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