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. 29struct UMutex; 30 31U_NAMESPACE_BEGIN 32struct UInitOnce; 33U_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 54U_NAMESPACE_BEGIN 55 56typedef std::atomic<int32_t> u_atomic_int32_t; 57#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val) 58 59inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 60 return var.load(std::memory_order_acquire); 61} 62 63inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 64 var.store(val, std::memory_order_release); 65} 66 67inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 68 return var->fetch_add(1) + 1; 69} 70 71inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 72 return var->fetch_sub(1) - 1; 73} 74U_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 97U_NAMESPACE_BEGIN 98typedef volatile LONG u_atomic_int32_t; 99#define ATOMIC_INT32_T_INITIALIZER(val) val 100 101inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 102 return InterlockedCompareExchange(&var, 0, 0); 103} 104 105inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 106 InterlockedExchange(&var, val); 107} 108 109 110inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 111 return InterlockedIncrement(var); 112} 113 114inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 115 return InterlockedDecrement(var); 116} 117U_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 125U_NAMESPACE_BEGIN 126typedef int32_t u_atomic_int32_t; 127#define ATOMIC_INT32_T_INITIALIZER(val) val 128 129inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 130 int32_t val = var; 131 __sync_synchronize(); 132 return val; 133} 134 135inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 136 __sync_synchronize(); 137 var = val; 138} 139 140inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) { 141 return __sync_add_and_fetch(p, 1); 142} 143 144inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) { 145 return __sync_sub_and_fetch(p, 1); 146} 147U_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 158U_NAMESPACE_BEGIN 159typedef int32_t u_atomic_int32_t; 160#define ATOMIC_INT32_T_INITIALIZER(val) val 161 162U_COMMON_API int32_t U_EXPORT2 163umtx_loadAcquire(u_atomic_int32_t &var); 164 165U_COMMON_API void U_EXPORT2 166umtx_storeRelease(u_atomic_int32_t &var, int32_t val); 167 168U_COMMON_API int32_t U_EXPORT2 169umtx_atomic_inc(u_atomic_int32_t *p); 170 171U_COMMON_API int32_t U_EXPORT2 172umtx_atomic_dec(u_atomic_int32_t *p); 173 174U_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 187U_NAMESPACE_BEGIN 188 189struct 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 201U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &); 202U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &); 203 204template<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. 217inline 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. 229inline 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. 248template<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. 260template<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 277U_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 322typedef 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 342struct UMutex { 343 pthread_mutex_t fMutex; 344}; 345typedef 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 */ 374U_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 */ 380U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); 381 382#endif /* UMUTEX_H */ 383/*eof*/ 384