]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.h
ICU-64243.0.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.h
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4**********************************************************************
2ca993e8 5* Copyright (C) 1997-2015, International Business Machines
b75a7d8f
A
6* Corporation and others. All Rights Reserved.
7**********************************************************************
8*
9* File UMUTEX.H
10*
11* Modification History:
12*
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******************************************************************************
18*/
19
20#ifndef UMUTEX_H
21#define UMUTEX_H
22
3d1f044b
A
23#include <atomic>
24#include <condition_variable>
25#include <mutex>
26
b75a7d8f 27#include "unicode/utypes.h"
4388f060 28#include "unicode/uclean.h"
3d1f044b
A
29#include "unicode/uobject.h"
30
4388f060 31#include "putilimp.h"
b75a7d8f 32
3d1f044b
A
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
37#endif
b75a7d8f 38
57a6839d 39
3d1f044b
A
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"
49 #endif
50template struct U_COMMON_API std::atomic<int32_t>;
51 #if defined(__clang__)
52 #pragma clang diagnostic pop
53 #endif
54#elif defined(__GNUC__)
55// For GCC this class is already exported/visible, so no need for U_COMMON_API.
56template struct std::atomic<int32_t>;
57#endif
58#endif
57a6839d 59
57a6839d 60
3d1f044b 61U_NAMESPACE_BEGIN
57a6839d
A
62
63/****************************************************************************
64 *
3d1f044b 65 * Low Level Atomic Operations, ICU wrappers for.
57a6839d
A
66 *
67 ****************************************************************************/
57a6839d
A
68
69typedef std::atomic<int32_t> u_atomic_int32_t;
70#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
71
72inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
73 return var.load(std::memory_order_acquire);
74}
75
76inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
77 var.store(val, std::memory_order_release);
78}
79
80inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
81 return var->fetch_add(1) + 1;
82}
83
84inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
85 return var->fetch_sub(1) - 1;
86}
57a6839d
A
87
88
89/*************************************************************************************************
b75a7d8f 90 *
57a6839d 91 * UInitOnce Definitions.
b75a7d8f 92 *
57a6839d
A
93 *************************************************************************************************/
94
57a6839d
A
95struct UInitOnce {
96 u_atomic_int32_t fState;
97 UErrorCode fErrCode;
3d1f044b
A
98 void reset() {fState = 0;}
99 UBool isReset() {return umtx_loadAcquire(fState) == 0;}
57a6839d
A
100// Note: isReset() is used by service registration code.
101// Thread safety of this usage needs review.
102};
103
104#define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
105
106
107U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
108U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
109
f3c0d7a5 110template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
57a6839d
A
111 if (umtx_loadAcquire(uio.fState) == 2) {
112 return;
113 }
114 if (umtx_initImplPreInit(uio)) {
115 (obj->*fp)();
116 umtx_initImplPostInit(uio);
117 }
118}
119
120
121// umtx_initOnce variant for plain functions, or static class functions.
122// No context parameter.
f3c0d7a5 123inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
57a6839d
A
124 if (umtx_loadAcquire(uio.fState) == 2) {
125 return;
126 }
127 if (umtx_initImplPreInit(uio)) {
128 (*fp)();
129 umtx_initImplPostInit(uio);
130 }
131}
132
133// umtx_initOnce variant for plain functions, or static class functions.
134// With ErrorCode, No context parameter.
f3c0d7a5 135inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
57a6839d
A
136 if (U_FAILURE(errCode)) {
137 return;
138 }
139 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
140 // We run the initialization.
141 (*fp)(errCode);
142 uio.fErrCode = errCode;
143 umtx_initImplPostInit(uio);
144 } else {
145 // Someone else already ran the initialization.
146 if (U_FAILURE(uio.fErrCode)) {
147 errCode = uio.fErrCode;
148 }
149 }
150}
151
152// umtx_initOnce variant for plain functions, or static class functions,
153// with a context parameter.
f3c0d7a5 154template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
57a6839d
A
155 if (umtx_loadAcquire(uio.fState) == 2) {
156 return;
157 }
158 if (umtx_initImplPreInit(uio)) {
159 (*fp)(context);
160 umtx_initImplPostInit(uio);
161 }
162}
163
164// umtx_initOnce variant for plain functions, or static class functions,
165// with a context parameter and an error code.
f3c0d7a5 166template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
57a6839d
A
167 if (U_FAILURE(errCode)) {
168 return;
169 }
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);
175 } else {
176 // Someone else already ran the initialization.
177 if (U_FAILURE(uio.fErrCode)) {
178 errCode = uio.fErrCode;
179 }
180 }
181}
182
57a6839d 183
3d1f044b
A
184/**
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.
b75a7d8f 188 *
3d1f044b
A
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.
57a6839d 193 *
3d1f044b
A
194 * UMutex *myMutex() {
195 * static UMutex *m = STATIC_NEW(UMutex);
196 * return m;
197 * }
198 * ...
199 *
200 * Mutex lock(myMutex()); // hold myMutex until the variable "lock" goes out of scope.
57a6839d
A
201 */
202
3d1f044b
A
203struct UMutex : public icu::UMemory {
204 UMutex() = default;
205 ~UMutex() = default;
206 UMutex(const UMutex &other) = delete;
207 UMutex &operator =(const UMutex &other) = delete;
51004dcb 208
3d1f044b
A
209 std::mutex fMutex = {}; // Note: struct - pubic members - because most access is from
210 // // plain C style functions (umtx_lock(), etc.)
51004dcb 211};
57a6839d 212
4388f060 213/* Lock a mutex.
374ca955
A
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.
b75a7d8f 217 */
57a6839d 218U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
b75a7d8f 219
51004dcb 220/* Unlock a mutex.
374ca955
A
221 * @param mutex The given mutex to be unlocked. Pass NULL to specify
222 * the global ICU mutex.
b75a7d8f 223 */
57a6839d 224U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
b75a7d8f 225
b331163b 226
3d1f044b 227U_NAMESPACE_END
b331163b 228
57a6839d 229#endif /* UMUTEX_H */
b75a7d8f 230/*eof*/