1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 **********************************************************************
5 * Copyright (C) 1997-2015, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 **********************************************************************
11 * Modification History:
13 * Date Name Description
14 * 04/02/97 aliu Creation.
15 * 04/07/99 srl rewrite - C interface, multiple mutices
16 * 05/13/99 stephen Changed to umutex (from cmutex)
17 ******************************************************************************
23 #include "unicode/utypes.h"
24 #include "unicode/uclean.h"
29 // Forward Declarations. UMutex is not in the ICU namespace (yet) because
30 // there are some remaining references from plain C.
38 // Stringify macros, to allow #include of user supplied atomic & mutex files.
39 #define U_MUTEX_STR(s) #s
40 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
42 /****************************************************************************
44 * Low Level Atomic Operations.
45 * Compiler dependent. Not operating system dependent.
47 ****************************************************************************/
48 #if defined (U_USER_ATOMICS_H)
49 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
51 #elif U_HAVE_STD_ATOMICS
53 // C++11 atomics are available.
59 typedef std::atomic<int32_t> u_atomic_int32_t;
60 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
62 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
63 return var.load(std::memory_order_acquire);
66 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
67 var.store(val, std::memory_order_release);
70 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
71 return var->fetch_add(1) + 1;
74 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
75 return var->fetch_sub(1) - 1;
79 #elif U_PLATFORM_HAS_WIN32_API
81 // MSVC compiler. Reads and writes of volatile variables have
82 // acquire and release memory semantics, respectively.
83 // This is a Microsoft extension, not standard C++ behavior.
85 // Update: can't use this because of MinGW, built with gcc.
86 // Original plan was to use gcc atomics for MinGW, but they
87 // aren't supported, so we fold MinGW into this path.
89 # define WIN32_LEAN_AND_MEAN
101 typedef volatile LONG u_atomic_int32_t;
102 #define ATOMIC_INT32_T_INITIALIZER(val) val
104 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
105 return InterlockedCompareExchange(&var, 0, 0);
108 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
109 InterlockedExchange(&var, val);
113 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
114 return InterlockedIncrement(var);
117 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
118 return InterlockedDecrement(var);
123 #elif U_HAVE_CLANG_ATOMICS
125 * Clang __c11 atomic built-ins
129 typedef _Atomic(int32_t) u_atomic_int32_t;
130 #define ATOMIC_INT32_T_INITIALIZER(val) val
132 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
133 return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
136 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
137 return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
141 return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
144 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
145 return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
150 #elif U_HAVE_GCC_ATOMICS
152 * gcc atomic ops. These are available on several other compilers as well.
156 typedef int32_t u_atomic_int32_t;
157 #define ATOMIC_INT32_T_INITIALIZER(val) val
159 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
161 __sync_synchronize();
165 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
166 __sync_synchronize();
170 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) {
171 return __sync_add_and_fetch(p, 1);
174 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) {
175 return __sync_sub_and_fetch(p, 1);
182 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
186 #define U_NO_PLATFORM_ATOMICS
189 typedef int32_t u_atomic_int32_t;
190 #define ATOMIC_INT32_T_INITIALIZER(val) val
192 U_COMMON_API int32_t U_EXPORT2
193 umtx_loadAcquire(u_atomic_int32_t &var);
195 U_COMMON_API void U_EXPORT2
196 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
198 U_COMMON_API int32_t U_EXPORT2
199 umtx_atomic_inc(u_atomic_int32_t *p);
201 U_COMMON_API int32_t U_EXPORT2
202 umtx_atomic_dec(u_atomic_int32_t *p);
206 #endif /* Low Level Atomic Ops Platfrom Chain */
210 /*************************************************************************************************
212 * UInitOnce Definitions.
213 * These are platform neutral.
215 *************************************************************************************************/
220 u_atomic_int32_t fState;
222 void reset() {fState = 0;};
223 UBool isReset() {return umtx_loadAcquire(fState) == 0;};
224 // Note: isReset() is used by service registration code.
225 // Thread safety of this usage needs review.
228 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
231 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
232 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
234 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
235 if (umtx_loadAcquire(uio.fState) == 2) {
238 if (umtx_initImplPreInit(uio)) {
240 umtx_initImplPostInit(uio);
245 // umtx_initOnce variant for plain functions, or static class functions.
246 // No context parameter.
247 inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
248 if (umtx_loadAcquire(uio.fState) == 2) {
251 if (umtx_initImplPreInit(uio)) {
253 umtx_initImplPostInit(uio);
257 // umtx_initOnce variant for plain functions, or static class functions.
258 // With ErrorCode, No context parameter.
259 inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
260 if (U_FAILURE(errCode)) {
263 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
264 // We run the initialization.
266 uio.fErrCode = errCode;
267 umtx_initImplPostInit(uio);
269 // Someone else already ran the initialization.
270 if (U_FAILURE(uio.fErrCode)) {
271 errCode = uio.fErrCode;
276 // umtx_initOnce variant for plain functions, or static class functions,
277 // with a context parameter.
278 template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
279 if (umtx_loadAcquire(uio.fState) == 2) {
282 if (umtx_initImplPreInit(uio)) {
284 umtx_initImplPostInit(uio);
288 // umtx_initOnce variant for plain functions, or static class functions,
289 // with a context parameter and an error code.
290 template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
291 if (U_FAILURE(errCode)) {
294 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
295 // We run the initialization.
296 (*fp)(context, errCode);
297 uio.fErrCode = errCode;
298 umtx_initImplPostInit(uio);
300 // Someone else already ran the initialization.
301 if (U_FAILURE(uio.fErrCode)) {
302 errCode = uio.fErrCode;
311 /*************************************************************************************************
313 * Mutex Definitions. Platform Dependent, #if platform chain follows.
314 * TODO: Add a C++11 version.
315 * Need to convert all mutex using files to C++ first.
317 *************************************************************************************************/
319 #if defined(U_USER_MUTEX_H)
320 // #inlcude "U_USER_MUTEX_H"
321 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
323 #elif U_PLATFORM_USES_ONLY_WIN32_API
325 /* For CRITICAL_SECTION */
328 * Note: there is an earlier include of windows.h in this file, but it is in
329 * different conditionals.
330 * This one is needed if we are using C++11 for atomic ops, but
331 * win32 APIs for Critical Sections.
334 # define WIN32_LEAN_AND_MEAN
335 # define VC_EXTRALEAN
343 # include <windows.h>
346 typedef struct UMutex {
347 icu::UInitOnce fInitOnce;
348 CRITICAL_SECTION fCS;
351 /* Initializer for a static UMUTEX. Deliberately contains no value for the
354 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
356 struct UConditionVar {
362 #define U_CONDITION_INITIALIZER {NULL, NULL, 0}
366 #elif U_PLATFORM_IMPLEMENTS_POSIX
375 pthread_mutex_t fMutex;
377 typedef struct UMutex UMutex;
378 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER}
380 struct UConditionVar {
381 pthread_cond_t fCondition;
383 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
388 * Unknow platform type.
389 * This is an error condition. ICU requires mutexes.
392 #error Unknown Platform.
398 /**************************************************************************************
400 * Mutex Implementation function declaratations.
401 * Declarations are platform neutral.
402 * Implementations, in umutex.cpp, are platform specific.
404 ************************************************************************************/
407 * @param mutex The given mutex to be locked. Pass NULL to specify
408 * the global ICU mutex. Recursive locks are an error
409 * and may cause a deadlock on some platforms.
411 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
414 * @param mutex The given mutex to be unlocked. Pass NULL to specify
415 * the global ICU mutex.
417 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
420 * Wait on a condition variable.
421 * The calling thread will unlock the mutex and wait on the condition variable.
422 * The mutex must be locked by the calling thread when invoking this function.
424 * @param cond the condition variable to wait on.
425 * @param mutex the associated mutex.
428 U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
432 * Broadcast wakeup of all threads waiting on a Condition.
433 * The associated mutex must be locked by the calling thread when calling
434 * this function; this is a temporary ICU restriction.
436 * @param cond the condition variable.
438 U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
441 * Signal a condition variable, waking up one waiting thread.
442 * CAUTION: Do not use. Place holder only. Not implemented for Windows.
444 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
446 #endif /* UMUTEX_H */