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> 96U_NAMESPACE_BEGIN 97typedef volatile LONG u_atomic_int32_t; 98#define ATOMIC_INT32_T_INITIALIZER(val) val 99 100inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 101 return InterlockedCompareExchange(&var, 0, 0); 102} 103 104inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 105 InterlockedExchange(&var, val); 106} 107 108 109inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 110 return InterlockedIncrement(var); 111} 112 113inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 114 return InterlockedDecrement(var); 115} 116U_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 123U_NAMESPACE_BEGIN 124typedef int32_t u_atomic_int32_t; 125#define ATOMIC_INT32_T_INITIALIZER(val) val 126 127inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 128 int32_t val = var; 129 __sync_synchronize(); 130 return val; 131} 132 133inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 134 __sync_synchronize(); 135 var = val; 136} 137 138inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) { 139 return __sync_add_and_fetch(p, 1); 140} 141 142inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) { 143 return __sync_sub_and_fetch(p, 1); 144} 145U_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 156U_NAMESPACE_BEGIN 157typedef int32_t u_atomic_int32_t; 158#define ATOMIC_INT32_T_INITIALIZER(val) val 159 160U_COMMON_API int32_t U_EXPORT2 161umtx_loadAcquire(u_atomic_int32_t &var); 162 163U_COMMON_API void U_EXPORT2 164umtx_storeRelease(u_atomic_int32_t &var, int32_t val); 165 166U_COMMON_API int32_t U_EXPORT2 167umtx_atomic_inc(u_atomic_int32_t *p); 168 169U_COMMON_API int32_t U_EXPORT2 170umtx_atomic_dec(u_atomic_int32_t *p); 171 172U_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 185U_NAMESPACE_BEGIN 186 187struct 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 199U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &); 200U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &); 201 202template<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. 215inline 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. 227inline 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. 246template<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. 258template<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 275U_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 320typedef 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 340struct UMutex { 341 pthread_mutex_t fMutex; 342}; 343typedef 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 */ 372U_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 */ 378U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); 379 380#endif /* UMUTEX_H */ 381/*eof*/ 382