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 ******************************************************************************
24 #include <condition_variable>
27 #include "unicode/utypes.h"
28 #include "unicode/uclean.h"
29 #include "unicode/uobject.h"
33 #if defined(U_USER_ATOMICS_H) || defined(U_USER_MUTEX_H)
34 // Support for including an alternate implementation of atomic & mutex operations has been withdrawn.
35 // See issue ICU-20185.
36 #error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
40 // Export an explicit template instantiation of std::atomic<int32_t>.
41 // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
42 // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
43 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
44 #if defined(__clang__) || defined(_MSC_VER)
45 #if defined(__clang__)
46 // Suppress the warning that the explicit instantiation after explicit specialization has no effect.
47 #pragma clang diagnostic push
48 #pragma clang diagnostic ignored "-Winstantiation-after-specialization"
50 template struct U_COMMON_API
std::atomic
<int32_t>;
51 #if defined(__clang__)
52 #pragma clang diagnostic pop
54 #elif defined(__GNUC__)
55 // For GCC this class is already exported/visible, so no need for U_COMMON_API.
56 template struct std::atomic
<int32_t>;
63 /****************************************************************************
65 * Low Level Atomic Operations, ICU wrappers for.
67 ****************************************************************************/
69 typedef std::atomic
<int32_t> u_atomic_int32_t
;
70 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
72 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
73 return var
.load(std::memory_order_acquire
);
76 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
77 var
.store(val
, std::memory_order_release
);
80 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*var
) {
81 return var
->fetch_add(1) + 1;
84 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*var
) {
85 return var
->fetch_sub(1) - 1;
89 /*************************************************************************************************
91 * UInitOnce Definitions.
93 *************************************************************************************************/
96 u_atomic_int32_t fState
;
98 void reset() {fState
= 0;}
99 UBool
isReset() {return umtx_loadAcquire(fState
) == 0;}
100 // Note: isReset() is used by service registration code.
101 // Thread safety of this usage needs review.
104 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
107 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce
&);
108 U_COMMON_API
void U_EXPORT2
umtx_initImplPostInit(UInitOnce
&);
110 template<class T
> void umtx_initOnce(UInitOnce
&uio
, T
*obj
, void (U_CALLCONV
T::*fp
)()) {
111 if (umtx_loadAcquire(uio
.fState
) == 2) {
114 if (umtx_initImplPreInit(uio
)) {
116 umtx_initImplPostInit(uio
);
121 // umtx_initOnce variant for plain functions, or static class functions.
122 // No context parameter.
123 inline void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)()) {
124 if (umtx_loadAcquire(uio
.fState
) == 2) {
127 if (umtx_initImplPreInit(uio
)) {
129 umtx_initImplPostInit(uio
);
133 // umtx_initOnce variant for plain functions, or static class functions.
134 // With ErrorCode, No context parameter.
135 inline void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)(UErrorCode
&), UErrorCode
&errCode
) {
136 if (U_FAILURE(errCode
)) {
139 if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) {
140 // We run the initialization.
142 uio
.fErrCode
= errCode
;
143 umtx_initImplPostInit(uio
);
145 // Someone else already ran the initialization.
146 if (U_FAILURE(uio
.fErrCode
)) {
147 errCode
= uio
.fErrCode
;
152 // umtx_initOnce variant for plain functions, or static class functions,
153 // with a context parameter.
154 template<class T
> void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)(T
), T context
) {
155 if (umtx_loadAcquire(uio
.fState
) == 2) {
158 if (umtx_initImplPreInit(uio
)) {
160 umtx_initImplPostInit(uio
);
164 // umtx_initOnce variant for plain functions, or static class functions,
165 // with a context parameter and an error code.
166 template<class T
> void umtx_initOnce(UInitOnce
&uio
, void (U_CALLCONV
*fp
)(T
, UErrorCode
&), T context
, UErrorCode
&errCode
) {
167 if (U_FAILURE(errCode
)) {
170 if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) {
171 // We run the initialization.
172 (*fp
)(context
, errCode
);
173 uio
.fErrCode
= errCode
;
174 umtx_initImplPostInit(uio
);
176 // Someone else already ran the initialization.
177 if (U_FAILURE(uio
.fErrCode
)) {
178 errCode
= uio
.fErrCode
;
185 * ICU Mutex wrappers. Originally wrapped operating system mutexes, giving the rest of ICU a
186 * platform independent set of mutex operations. Now vestigial, wrapping std::mutex only.
187 * For internal ICU use only.
189 * Caution: do not directly declare static or global instances of UMutex. Doing so can introduce
190 * static initializers, which are disallowed in ICU library code. Instead, use the following
191 * idiom, which avoids static init and also avoids ordering issues on destruction
192 * (use after delete) by avoiding destruction altogether.
194 * UMutex *myMutex() {
195 * static UMutex *m = STATIC_NEW(UMutex);
200 * Mutex lock(myMutex()); // hold myMutex until the variable "lock" goes out of scope.
203 struct UMutex
: public icu::UMemory
{
206 UMutex(const UMutex
&other
) = delete;
207 UMutex
&operator =(const UMutex
&other
) = delete;
209 std::mutex fMutex
= {}; // Note: struct - pubic members - because most access is from
210 // // plain C style functions (umtx_lock(), etc.)
214 * @param mutex The given mutex to be locked. Pass NULL to specify
215 * the global ICU mutex. Recursive locks are an error
216 * and may cause a deadlock on some platforms.
218 U_INTERNAL
void U_EXPORT2
umtx_lock(UMutex
* mutex
);
221 * @param mutex The given mutex to be unlocked. Pass NULL to specify
222 * the global ICU mutex.
224 U_INTERNAL
void U_EXPORT2
umtx_unlock (UMutex
* mutex
);
229 #endif /* UMUTEX_H */