1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/common/umutex.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,383 @@ 1.4 +/* 1.5 +********************************************************************** 1.6 +* Copyright (C) 1997-2013, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +********************************************************************** 1.9 +* 1.10 +* File UMUTEX.H 1.11 +* 1.12 +* Modification History: 1.13 +* 1.14 +* Date Name Description 1.15 +* 04/02/97 aliu Creation. 1.16 +* 04/07/99 srl rewrite - C interface, multiple mutices 1.17 +* 05/13/99 stephen Changed to umutex (from cmutex) 1.18 +****************************************************************************** 1.19 +*/ 1.20 + 1.21 +#ifndef UMUTEX_H 1.22 +#define UMUTEX_H 1.23 + 1.24 +#include "unicode/utypes.h" 1.25 +#include "unicode/uclean.h" 1.26 +#include "putilimp.h" 1.27 + 1.28 + 1.29 + 1.30 +// Forward Declarations. UMutex is not in the ICU namespace (yet) because 1.31 +// there are some remaining references from plain C. 1.32 +struct UMutex; 1.33 + 1.34 +U_NAMESPACE_BEGIN 1.35 +struct UInitOnce; 1.36 +U_NAMESPACE_END 1.37 + 1.38 +// Stringify macros, to allow #include of user supplied atomic & mutex files. 1.39 +#define U_MUTEX_STR(s) #s 1.40 +#define U_MUTEX_XSTR(s) U_MUTEX_STR(s) 1.41 + 1.42 +/**************************************************************************** 1.43 + * 1.44 + * Low Level Atomic Operations. 1.45 + * Compiler dependent. Not operating system dependent. 1.46 + * 1.47 + ****************************************************************************/ 1.48 +#if defined (U_USER_ATOMICS_H) 1.49 +#include U_MUTEX_XSTR(U_USER_ATOMICS_H) 1.50 + 1.51 +#elif U_HAVE_STD_ATOMICS 1.52 + 1.53 +// C++11 atomics are available. 1.54 + 1.55 +#include <atomic> 1.56 + 1.57 +U_NAMESPACE_BEGIN 1.58 + 1.59 +typedef std::atomic<int32_t> u_atomic_int32_t; 1.60 +#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val) 1.61 + 1.62 +inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 1.63 + return var.load(std::memory_order_acquire); 1.64 +} 1.65 + 1.66 +inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 1.67 + var.store(val, std::memory_order_release); 1.68 +} 1.69 + 1.70 +inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 1.71 + return var->fetch_add(1) + 1; 1.72 +} 1.73 + 1.74 +inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 1.75 + return var->fetch_sub(1) - 1; 1.76 +} 1.77 +U_NAMESPACE_END 1.78 + 1.79 +#elif U_PLATFORM_HAS_WIN32_API 1.80 + 1.81 +// MSVC compiler. Reads and writes of volatile variables have 1.82 +// acquire and release memory semantics, respectively. 1.83 +// This is a Microsoft extension, not standard C++ behavior. 1.84 +// 1.85 +// Update: can't use this because of MinGW, built with gcc. 1.86 +// Original plan was to use gcc atomics for MinGW, but they 1.87 +// aren't supported, so we fold MinGW into this path. 1.88 + 1.89 +# define WIN32_LEAN_AND_MEAN 1.90 +# define VC_EXTRALEAN 1.91 +# define NOUSER 1.92 +# define NOSERVICE 1.93 +# define NOIME 1.94 +# define NOMCX 1.95 +# ifndef NOMINMAX 1.96 +# define NOMINMAX 1.97 +# endif 1.98 +# include <windows.h> 1.99 + 1.100 +U_NAMESPACE_BEGIN 1.101 +typedef volatile LONG u_atomic_int32_t; 1.102 +#define ATOMIC_INT32_T_INITIALIZER(val) val 1.103 + 1.104 +inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 1.105 + return InterlockedCompareExchange(&var, 0, 0); 1.106 +} 1.107 + 1.108 +inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 1.109 + InterlockedExchange(&var, val); 1.110 +} 1.111 + 1.112 + 1.113 +inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { 1.114 + return InterlockedIncrement(var); 1.115 +} 1.116 + 1.117 +inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { 1.118 + return InterlockedDecrement(var); 1.119 +} 1.120 +U_NAMESPACE_END 1.121 + 1.122 + 1.123 +#elif U_HAVE_GCC_ATOMICS 1.124 +/* 1.125 + * gcc atomic ops. These are available on several other compilers as well. 1.126 + */ 1.127 + 1.128 +U_NAMESPACE_BEGIN 1.129 +typedef int32_t u_atomic_int32_t; 1.130 +#define ATOMIC_INT32_T_INITIALIZER(val) val 1.131 + 1.132 +inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { 1.133 + int32_t val = var; 1.134 + __sync_synchronize(); 1.135 + return val; 1.136 +} 1.137 + 1.138 +inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { 1.139 + __sync_synchronize(); 1.140 + var = val; 1.141 +} 1.142 + 1.143 +inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) { 1.144 + return __sync_add_and_fetch(p, 1); 1.145 +} 1.146 + 1.147 +inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) { 1.148 + return __sync_sub_and_fetch(p, 1); 1.149 +} 1.150 +U_NAMESPACE_END 1.151 + 1.152 +#else 1.153 + 1.154 +/* 1.155 + * Unknown Platform. Use out-of-line functions, which in turn use mutexes. 1.156 + * Slow but correct. 1.157 + */ 1.158 + 1.159 +#define U_NO_PLATFORM_ATOMICS 1.160 + 1.161 +U_NAMESPACE_BEGIN 1.162 +typedef int32_t u_atomic_int32_t; 1.163 +#define ATOMIC_INT32_T_INITIALIZER(val) val 1.164 + 1.165 +U_COMMON_API int32_t U_EXPORT2 1.166 +umtx_loadAcquire(u_atomic_int32_t &var); 1.167 + 1.168 +U_COMMON_API void U_EXPORT2 1.169 +umtx_storeRelease(u_atomic_int32_t &var, int32_t val); 1.170 + 1.171 +U_COMMON_API int32_t U_EXPORT2 1.172 +umtx_atomic_inc(u_atomic_int32_t *p); 1.173 + 1.174 +U_COMMON_API int32_t U_EXPORT2 1.175 +umtx_atomic_dec(u_atomic_int32_t *p); 1.176 + 1.177 +U_NAMESPACE_END 1.178 + 1.179 +#endif /* Low Level Atomic Ops Platfrom Chain */ 1.180 + 1.181 + 1.182 + 1.183 +/************************************************************************************************* 1.184 + * 1.185 + * UInitOnce Definitions. 1.186 + * These are platform neutral. 1.187 + * 1.188 + *************************************************************************************************/ 1.189 + 1.190 +U_NAMESPACE_BEGIN 1.191 + 1.192 +struct UInitOnce { 1.193 + u_atomic_int32_t fState; 1.194 + UErrorCode fErrCode; 1.195 + void reset() {fState = 0;}; 1.196 + UBool isReset() {return umtx_loadAcquire(fState) == 0;}; 1.197 +// Note: isReset() is used by service registration code. 1.198 +// Thread safety of this usage needs review. 1.199 +}; 1.200 + 1.201 +#define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR} 1.202 + 1.203 + 1.204 +U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &); 1.205 +U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &); 1.206 + 1.207 +template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) { 1.208 + if (umtx_loadAcquire(uio.fState) == 2) { 1.209 + return; 1.210 + } 1.211 + if (umtx_initImplPreInit(uio)) { 1.212 + (obj->*fp)(); 1.213 + umtx_initImplPostInit(uio); 1.214 + } 1.215 +} 1.216 + 1.217 + 1.218 +// umtx_initOnce variant for plain functions, or static class functions. 1.219 +// No context parameter. 1.220 +inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) { 1.221 + if (umtx_loadAcquire(uio.fState) == 2) { 1.222 + return; 1.223 + } 1.224 + if (umtx_initImplPreInit(uio)) { 1.225 + (*fp)(); 1.226 + umtx_initImplPostInit(uio); 1.227 + } 1.228 +} 1.229 + 1.230 +// umtx_initOnce variant for plain functions, or static class functions. 1.231 +// With ErrorCode, No context parameter. 1.232 +inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) { 1.233 + if (U_FAILURE(errCode)) { 1.234 + return; 1.235 + } 1.236 + if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { 1.237 + // We run the initialization. 1.238 + (*fp)(errCode); 1.239 + uio.fErrCode = errCode; 1.240 + umtx_initImplPostInit(uio); 1.241 + } else { 1.242 + // Someone else already ran the initialization. 1.243 + if (U_FAILURE(uio.fErrCode)) { 1.244 + errCode = uio.fErrCode; 1.245 + } 1.246 + } 1.247 +} 1.248 + 1.249 +// umtx_initOnce variant for plain functions, or static class functions, 1.250 +// with a context parameter. 1.251 +template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) { 1.252 + if (umtx_loadAcquire(uio.fState) == 2) { 1.253 + return; 1.254 + } 1.255 + if (umtx_initImplPreInit(uio)) { 1.256 + (*fp)(context); 1.257 + umtx_initImplPostInit(uio); 1.258 + } 1.259 +} 1.260 + 1.261 +// umtx_initOnce variant for plain functions, or static class functions, 1.262 +// with a context parameter and an error code. 1.263 +template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) { 1.264 + if (U_FAILURE(errCode)) { 1.265 + return; 1.266 + } 1.267 + if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { 1.268 + // We run the initialization. 1.269 + (*fp)(context, errCode); 1.270 + uio.fErrCode = errCode; 1.271 + umtx_initImplPostInit(uio); 1.272 + } else { 1.273 + // Someone else already ran the initialization. 1.274 + if (U_FAILURE(uio.fErrCode)) { 1.275 + errCode = uio.fErrCode; 1.276 + } 1.277 + } 1.278 +} 1.279 + 1.280 +U_NAMESPACE_END 1.281 + 1.282 + 1.283 + 1.284 +/************************************************************************************************* 1.285 + * 1.286 + * Mutex Definitions. Platform Dependent, #if platform chain follows. 1.287 + * TODO: Add a C++11 version. 1.288 + * Need to convert all mutex using files to C++ first. 1.289 + * 1.290 + *************************************************************************************************/ 1.291 + 1.292 +#if defined(U_USER_MUTEX_H) 1.293 +// #inlcude "U_USER_MUTEX_H" 1.294 +#include U_MUTEX_XSTR(U_USER_MUTEX_H) 1.295 + 1.296 +#elif U_PLATFORM_HAS_WIN32_API 1.297 + 1.298 +/* Windows Definitions. 1.299 + * Windows comes first in the platform chain. 1.300 + * Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case. 1.301 + */ 1.302 + 1.303 + 1.304 +/* For CRITICAL_SECTION */ 1.305 + 1.306 +/* 1.307 + * Note: there is an earlier include of windows.h in this file, but it is in 1.308 + * different conditionals. 1.309 + * This one is needed if we are using C++11 for atomic ops, but 1.310 + * win32 APIs for Critical Sections. 1.311 + */ 1.312 + 1.313 +# define WIN32_LEAN_AND_MEAN 1.314 +# define VC_EXTRALEAN 1.315 +# define NOUSER 1.316 +# define NOSERVICE 1.317 +# define NOIME 1.318 +# define NOMCX 1.319 +# ifndef NOMINMAX 1.320 +# define NOMINMAX 1.321 +# endif 1.322 +# include <windows.h> 1.323 + 1.324 + 1.325 +typedef struct UMutex { 1.326 + icu::UInitOnce fInitOnce; 1.327 + CRITICAL_SECTION fCS; 1.328 +} UMutex; 1.329 + 1.330 +/* Initializer for a static UMUTEX. Deliberately contains no value for the 1.331 + * CRITICAL_SECTION. 1.332 + */ 1.333 +#define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER} 1.334 + 1.335 + 1.336 + 1.337 +#elif U_PLATFORM_IMPLEMENTS_POSIX 1.338 + 1.339 +/* 1.340 + * POSIX platform 1.341 + */ 1.342 + 1.343 +#include <pthread.h> 1.344 + 1.345 +struct UMutex { 1.346 + pthread_mutex_t fMutex; 1.347 +}; 1.348 +typedef struct UMutex UMutex; 1.349 +#define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER} 1.350 + 1.351 +#else 1.352 + 1.353 +/* 1.354 + * Unknow platform type. 1.355 + * This is an error condition. ICU requires mutexes. 1.356 + */ 1.357 + 1.358 +#error Unknown Platform. 1.359 + 1.360 +#endif 1.361 + 1.362 + 1.363 + 1.364 +/************************************************************************************** 1.365 + * 1.366 + * Mutex Implementation function declaratations. 1.367 + * Declarations are platform neutral. 1.368 + * Implementations, in umutex.cpp, are platform specific. 1.369 + * 1.370 + ************************************************************************************/ 1.371 + 1.372 +/* Lock a mutex. 1.373 + * @param mutex The given mutex to be locked. Pass NULL to specify 1.374 + * the global ICU mutex. Recursive locks are an error 1.375 + * and may cause a deadlock on some platforms. 1.376 + */ 1.377 +U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex); 1.378 + 1.379 +/* Unlock a mutex. 1.380 + * @param mutex The given mutex to be unlocked. Pass NULL to specify 1.381 + * the global ICU mutex. 1.382 + */ 1.383 +U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); 1.384 + 1.385 +#endif /* UMUTEX_H */ 1.386 +/*eof*/