2 ********************************************************************** 
   3 *   Copyright (C) 1997-2015, International Business Machines 
   4 *   Corporation and others.  All Rights Reserved. 
   5 ********************************************************************** 
   9 * Modification History: 
  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 ****************************************************************************** 
  21 #include "unicode/utypes.h" 
  22 #include "unicode/uclean.h" 
  27 // Forward Declarations. UMutex is not in the ICU namespace (yet) because 
  28 //                       there are some remaining references from plain C. 
  36 // Stringify macros, to allow #include of user supplied atomic & mutex files. 
  37 #define U_MUTEX_STR(s) #s 
  38 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s) 
  40 /**************************************************************************** 
  42  *   Low Level Atomic Operations. 
  43  *      Compiler dependent. Not operating system dependent. 
  45  ****************************************************************************/ 
  46 #if defined (U_USER_ATOMICS_H) 
  47 #include U_MUTEX_XSTR(U_USER_ATOMICS_H) 
  49 #elif U_HAVE_STD_ATOMICS 
  51 //  C++11 atomics are available. 
  57 typedef std::atomic
<int32_t> u_atomic_int32_t
; 
  58 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val) 
  60 inline int32_t umtx_loadAcquire(u_atomic_int32_t 
&var
) { 
  61     return var
.load(std::memory_order_acquire
); 
  64 inline void umtx_storeRelease(u_atomic_int32_t 
&var
, int32_t val
) { 
  65     var
.store(val
, std::memory_order_release
); 
  68 inline int32_t umtx_atomic_inc(u_atomic_int32_t 
*var
) { 
  69     return var
->fetch_add(1) + 1; 
  72 inline int32_t umtx_atomic_dec(u_atomic_int32_t 
*var
) { 
  73     return var
->fetch_sub(1) - 1; 
  77 #elif U_PLATFORM_HAS_WIN32_API 
  79 // MSVC compiler. Reads and writes of volatile variables have 
  80 //                acquire and release memory semantics, respectively. 
  81 //                This is a Microsoft extension, not standard C++ behavior. 
  83 //   Update:      can't use this because of MinGW, built with gcc. 
  84 //                Original plan was to use gcc atomics for MinGW, but they 
  85 //                aren't supported, so we fold MinGW into this path. 
  87 # define WIN32_LEAN_AND_MEAN 
  99 typedef volatile LONG u_atomic_int32_t
; 
 100 #define ATOMIC_INT32_T_INITIALIZER(val) val 
 102 inline int32_t umtx_loadAcquire(u_atomic_int32_t 
&var
) { 
 103     return InterlockedCompareExchange(&var
, 0, 0); 
 106 inline void umtx_storeRelease(u_atomic_int32_t 
&var
, int32_t val
) { 
 107     InterlockedExchange(&var
, val
); 
 111 inline int32_t umtx_atomic_inc(u_atomic_int32_t 
*var
) { 
 112     return InterlockedIncrement(var
); 
 115 inline int32_t umtx_atomic_dec(u_atomic_int32_t 
*var
) { 
 116     return InterlockedDecrement(var
); 
 121 #elif U_HAVE_CLANG_ATOMICS 
 123  *  Clang __c11 atomic built-ins 
 127 typedef _Atomic(int32_t) u_atomic_int32_t
; 
 128 #define ATOMIC_INT32_T_INITIALIZER(val) val 
 130 inline int32_t umtx_loadAcquire(u_atomic_int32_t 
&var
) { 
 131      return __c11_atomic_load(&var
, __ATOMIC_ACQUIRE
); 
 134 inline void umtx_storeRelease(u_atomic_int32_t 
&var
, int32_t val
) { 
 135    return __c11_atomic_store(&var
, val
, __ATOMIC_RELEASE
); 
 138 inline int32_t umtx_atomic_inc(u_atomic_int32_t 
*var
) { 
 139     return __c11_atomic_fetch_add(var
, 1, __ATOMIC_SEQ_CST
) + 1; 
 142 inline int32_t umtx_atomic_dec(u_atomic_int32_t 
*var
) { 
 143     return __c11_atomic_fetch_sub(var
, 1, __ATOMIC_SEQ_CST
) - 1; 
 148 #elif U_HAVE_GCC_ATOMICS 
 150  * gcc atomic ops. These are available on several other compilers as well. 
 154 typedef int32_t u_atomic_int32_t
; 
 155 #define ATOMIC_INT32_T_INITIALIZER(val) val 
 157 inline int32_t umtx_loadAcquire(u_atomic_int32_t 
&var
) { 
 159     __sync_synchronize(); 
 163 inline void umtx_storeRelease(u_atomic_int32_t 
&var
, int32_t val
) { 
 164     __sync_synchronize(); 
 168 inline int32_t umtx_atomic_inc(u_atomic_int32_t 
*p
)  { 
 169    return __sync_add_and_fetch(p
, 1); 
 172 inline int32_t umtx_atomic_dec(u_atomic_int32_t 
*p
)  { 
 173    return __sync_sub_and_fetch(p
, 1); 
 180  * Unknown Platform. Use out-of-line functions, which in turn use mutexes. 
 184 #define U_NO_PLATFORM_ATOMICS 
 187 typedef int32_t u_atomic_int32_t
; 
 188 #define ATOMIC_INT32_T_INITIALIZER(val) val 
 190 U_COMMON_API 
int32_t U_EXPORT2 
 
 191 umtx_loadAcquire(u_atomic_int32_t 
&var
); 
 193 U_COMMON_API 
void U_EXPORT2 
 
 194 umtx_storeRelease(u_atomic_int32_t 
&var
, int32_t val
); 
 196 U_COMMON_API 
int32_t U_EXPORT2 
 
 197 umtx_atomic_inc(u_atomic_int32_t 
*p
); 
 199 U_COMMON_API 
int32_t U_EXPORT2 
 
 200 umtx_atomic_dec(u_atomic_int32_t 
*p
); 
 204 #endif  /* Low Level Atomic Ops Platfrom Chain */ 
 208 /************************************************************************************************* 
 210  *  UInitOnce Definitions. 
 211  *     These are platform neutral. 
 213  *************************************************************************************************/ 
 218     u_atomic_int32_t   fState
; 
 220     void reset() {fState 
= 0;}; 
 221     UBool 
isReset() {return umtx_loadAcquire(fState
) == 0;}; 
 222 // Note: isReset() is used by service registration code. 
 223 //                 Thread safety of this usage needs review. 
 226 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR} 
 229 U_COMMON_API UBool U_EXPORT2 
umtx_initImplPreInit(UInitOnce 
&); 
 230 U_COMMON_API 
void  U_EXPORT2 
umtx_initImplPostInit(UInitOnce 
&); 
 232 template<class T
> void umtx_initOnce(UInitOnce 
&uio
, T 
*obj
, void (T::*fp
)()) { 
 233     if (umtx_loadAcquire(uio
.fState
) == 2) { 
 236     if (umtx_initImplPreInit(uio
)) { 
 238         umtx_initImplPostInit(uio
); 
 243 // umtx_initOnce variant for plain functions, or static class functions. 
 244 //               No context parameter. 
 245 inline void umtx_initOnce(UInitOnce 
&uio
, void (*fp
)()) { 
 246     if (umtx_loadAcquire(uio
.fState
) == 2) { 
 249     if (umtx_initImplPreInit(uio
)) { 
 251         umtx_initImplPostInit(uio
); 
 255 // umtx_initOnce variant for plain functions, or static class functions. 
 256 //               With ErrorCode, No context parameter. 
 257 inline void umtx_initOnce(UInitOnce 
&uio
, void (*fp
)(UErrorCode 
&), UErrorCode 
&errCode
) { 
 258     if (U_FAILURE(errCode
)) { 
 261     if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) { 
 262         // We run the initialization. 
 264         uio
.fErrCode 
= errCode
; 
 265         umtx_initImplPostInit(uio
); 
 267         // Someone else already ran the initialization. 
 268         if (U_FAILURE(uio
.fErrCode
)) { 
 269             errCode 
= uio
.fErrCode
; 
 274 // umtx_initOnce variant for plain functions, or static class functions, 
 275 //               with a context parameter. 
 276 template<class T
> void umtx_initOnce(UInitOnce 
&uio
, void (*fp
)(T
), T context
) { 
 277     if (umtx_loadAcquire(uio
.fState
) == 2) { 
 280     if (umtx_initImplPreInit(uio
)) { 
 282         umtx_initImplPostInit(uio
); 
 286 // umtx_initOnce variant for plain functions, or static class functions, 
 287 //               with a context parameter and an error code. 
 288 template<class T
> void umtx_initOnce(UInitOnce 
&uio
, void (*fp
)(T
, UErrorCode 
&), T context
, UErrorCode 
&errCode
) { 
 289     if (U_FAILURE(errCode
)) { 
 292     if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) { 
 293         // We run the initialization. 
 294         (*fp
)(context
, errCode
); 
 295         uio
.fErrCode 
= errCode
; 
 296         umtx_initImplPostInit(uio
); 
 298         // Someone else already ran the initialization. 
 299         if (U_FAILURE(uio
.fErrCode
)) { 
 300             errCode 
= uio
.fErrCode
; 
 309 /************************************************************************************************* 
 311  *  Mutex Definitions. Platform Dependent, #if platform chain follows. 
 312  *         TODO:  Add a C++11 version. 
 313  *                Need to convert all mutex using files to C++ first. 
 315  *************************************************************************************************/ 
 317 #if defined(U_USER_MUTEX_H) 
 318 // #inlcude "U_USER_MUTEX_H" 
 319 #include U_MUTEX_XSTR(U_USER_MUTEX_H) 
 321 #elif U_PLATFORM_HAS_WIN32_API 
 323 /* Windows Definitions. 
 324  *    Windows comes first in the platform chain. 
 325  *    Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case. 
 329 /* For CRITICAL_SECTION */ 
 332  *   Note: there is an earlier include of windows.h in this file, but it is in 
 333  *         different conditionals. 
 334  *         This one is needed if we are using C++11 for atomic ops, but 
 335  *         win32 APIs for Critical Sections. 
 338 # define WIN32_LEAN_AND_MEAN 
 339 # define VC_EXTRALEAN 
 347 # include <windows.h> 
 350 typedef struct UMutex 
{ 
 351     icu::UInitOnce    fInitOnce
; 
 352     CRITICAL_SECTION  fCS
; 
 355 /* Initializer for a static UMUTEX. Deliberately contains no value for the 
 358 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER} 
 360 struct UConditionVar 
{ 
 366 #define U_CONDITION_INITIALIZER {NULL, NULL, 0} 
 370 #elif U_PLATFORM_IMPLEMENTS_POSIX 
 379     pthread_mutex_t  fMutex
; 
 381 typedef struct UMutex UMutex
; 
 382 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER} 
 384 struct UConditionVar 
{ 
 385     pthread_cond_t   fCondition
; 
 387 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER} 
 392  *  Unknow platform type. 
 393  *      This is an error condition. ICU requires mutexes. 
 396 #error Unknown Platform. 
 402 /************************************************************************************** 
 404  *  Mutex Implementation function declaratations. 
 405  *     Declarations are platform neutral. 
 406  *     Implementations, in umutex.cpp, are platform specific. 
 408  ************************************************************************************/ 
 411  * @param mutex The given mutex to be locked.  Pass NULL to specify 
 412  *              the global ICU mutex.  Recursive locks are an error 
 413  *              and may cause a deadlock on some platforms. 
 415 U_INTERNAL 
void U_EXPORT2 
umtx_lock(UMutex
* mutex
); 
 418  * @param mutex The given mutex to be unlocked.  Pass NULL to specify 
 419  *              the global ICU mutex. 
 421 U_INTERNAL 
void U_EXPORT2 
umtx_unlock (UMutex
* mutex
); 
 424  * Wait on a condition variable. 
 425  * The calling thread will unlock the mutex and wait on the condition variable. 
 426  * The mutex must be locked by the calling thread when invoking this function. 
 428  * @param cond the condition variable to wait on. 
 429  * @param mutex the associated mutex. 
 432 U_INTERNAL 
void U_EXPORT2 
umtx_condWait(UConditionVar 
*cond
, UMutex 
*mutex
); 
 436  * Broadcast wakeup of all threads waiting on a Condition. 
 437  * The associated mutex must be locked by the calling thread when calling 
 438  * this function; this is a temporary ICU restriction. 
 440  * @param cond the condition variable. 
 442 U_INTERNAL 
void U_EXPORT2 
umtx_condBroadcast(UConditionVar 
*cond
); 
 445  * Signal a condition variable, waking up one waiting thread. 
 446  * CAUTION: Do not use. Place holder only. Not implemented for Windows. 
 448 U_INTERNAL 
void U_EXPORT2 
umtx_condSignal(UConditionVar 
*cond
); 
 450 #endif /* UMUTEX_H */