1 // © 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 #ifndef WIN32_LEAN_AND_MEAN
90 # define WIN32_LEAN_AND_MEAN
100 # include <windows.h>
103 typedef volatile LONG u_atomic_int32_t
;
104 #define ATOMIC_INT32_T_INITIALIZER(val) val
106 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
107 return InterlockedCompareExchange(&var
, 0, 0);
110 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
111 InterlockedExchange(&var
, val
);
115 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*var
) {
116 return InterlockedIncrement(var
);
119 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*var
) {
120 return InterlockedDecrement(var
);
125 #elif U_HAVE_CLANG_ATOMICS
127 * Clang __c11 atomic built-ins
131 typedef _Atomic(int32_t) u_atomic_int32_t
;
132 #define ATOMIC_INT32_T_INITIALIZER(val) val
134 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
135 return __c11_atomic_load(&var
, __ATOMIC_ACQUIRE
);
138 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
139 return __c11_atomic_store(&var
, val
, __ATOMIC_RELEASE
);
142 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*var
) {
143 return __c11_atomic_fetch_add(var
, 1, __ATOMIC_SEQ_CST
) + 1;
146 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*var
) {
147 return __c11_atomic_fetch_sub(var
, 1, __ATOMIC_SEQ_CST
) - 1;
152 #elif U_HAVE_GCC_ATOMICS
154 * gcc atomic ops. These are available on several other compilers as well.
158 typedef int32_t u_atomic_int32_t
;
159 #define ATOMIC_INT32_T_INITIALIZER(val) val
161 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
163 __sync_synchronize();
167 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
168 __sync_synchronize();
172 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*p
) {
173 return __sync_add_and_fetch(p
, 1);
176 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*p
) {
177 return __sync_sub_and_fetch(p
, 1);
184 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
188 #define U_NO_PLATFORM_ATOMICS
191 typedef int32_t u_atomic_int32_t
;
192 #define ATOMIC_INT32_T_INITIALIZER(val) val
194 U_COMMON_API
int32_t U_EXPORT2
195 umtx_loadAcquire(u_atomic_int32_t
&var
);
197 U_COMMON_API
void U_EXPORT2
198 umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
);
200 U_COMMON_API
int32_t U_EXPORT2
201 umtx_atomic_inc(u_atomic_int32_t
*p
);
203 U_COMMON_API
int32_t U_EXPORT2
204 umtx_atomic_dec(u_atomic_int32_t
*p
);
208 #endif /* Low Level Atomic Ops Platfrom Chain */
212 /*************************************************************************************************
214 * UInitOnce Definitions.
215 * These are platform neutral.
217 *************************************************************************************************/
222 u_atomic_int32_t fState
;
224 void reset() {fState
= 0;};
225 UBool
isReset() {return umtx_loadAcquire(fState
) == 0;};
226 // Note: isReset() is used by service registration code.
227 // Thread safety of this usage needs review.
230 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
233 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce
&);
234 U_COMMON_API
void U_EXPORT2
umtx_initImplPostInit(UInitOnce
&);
236 template<class T
> void umtx_initOnce(UInitOnce
&uio
, T
*obj
, void (U_CALLCONV
T::*fp
)()) {
237 if (umtx_loadAcquire(uio
.fState
) == 2) {
240 if (umtx_initImplPreInit(uio
)) {
242 umtx_initImplPostInit(uio
);
247 // umtx_initOnce variant for plain functions, or static class functions.
248 // No context parameter.
249 inline void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)()) {
250 if (umtx_loadAcquire(uio
.fState
) == 2) {
253 if (umtx_initImplPreInit(uio
)) {
255 umtx_initImplPostInit(uio
);
259 // umtx_initOnce variant for plain functions, or static class functions.
260 // With ErrorCode, No context parameter.
261 inline void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)(UErrorCode
&), UErrorCode
&errCode
) {
262 if (U_FAILURE(errCode
)) {
265 if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) {
266 // We run the initialization.
268 uio
.fErrCode
= errCode
;
269 umtx_initImplPostInit(uio
);
271 // Someone else already ran the initialization.
272 if (U_FAILURE(uio
.fErrCode
)) {
273 errCode
= uio
.fErrCode
;
278 // umtx_initOnce variant for plain functions, or static class functions,
279 // with a context parameter.
280 template<class T
> void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)(T
), T context
) {
281 if (umtx_loadAcquire(uio
.fState
) == 2) {
284 if (umtx_initImplPreInit(uio
)) {
286 umtx_initImplPostInit(uio
);
290 // umtx_initOnce variant for plain functions, or static class functions,
291 // with a context parameter and an error code.
292 template<class T
> void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)(T
, UErrorCode
&), T context
, UErrorCode
&errCode
) {
293 if (U_FAILURE(errCode
)) {
296 if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) {
297 // We run the initialization.
298 (*fp
)(context
, errCode
);
299 uio
.fErrCode
= errCode
;
300 umtx_initImplPostInit(uio
);
302 // Someone else already ran the initialization.
303 if (U_FAILURE(uio
.fErrCode
)) {
304 errCode
= uio
.fErrCode
;
313 /*************************************************************************************************
315 * Mutex Definitions. Platform Dependent, #if platform chain follows.
316 * TODO: Add a C++11 version.
317 * Need to convert all mutex using files to C++ first.
319 *************************************************************************************************/
321 #if defined(U_USER_MUTEX_H)
322 // #inlcude "U_USER_MUTEX_H"
323 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
325 #elif U_PLATFORM_USES_ONLY_WIN32_API
327 /* For CRITICAL_SECTION */
330 * Note: there is an earlier include of windows.h in this file, but it is in
331 * different conditionals.
332 * This one is needed if we are using C++11 for atomic ops, but
333 * win32 APIs for Critical Sections.
336 #ifndef WIN32_LEAN_AND_MEAN
337 # 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 */