xref: /aosp_15_r20/external/icu/libicu/cts_headers/umutex.h (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1*0e209d39SAndroid Build Coastguard Worker // © 2016 and later: Unicode, Inc. and others.
2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html
3*0e209d39SAndroid Build Coastguard Worker /*
4*0e209d39SAndroid Build Coastguard Worker **********************************************************************
5*0e209d39SAndroid Build Coastguard Worker *   Copyright (C) 1997-2015, International Business Machines
6*0e209d39SAndroid Build Coastguard Worker *   Corporation and others.  All Rights Reserved.
7*0e209d39SAndroid Build Coastguard Worker **********************************************************************
8*0e209d39SAndroid Build Coastguard Worker *
9*0e209d39SAndroid Build Coastguard Worker * File UMUTEX.H
10*0e209d39SAndroid Build Coastguard Worker *
11*0e209d39SAndroid Build Coastguard Worker * Modification History:
12*0e209d39SAndroid Build Coastguard Worker *
13*0e209d39SAndroid Build Coastguard Worker *   Date        Name        Description
14*0e209d39SAndroid Build Coastguard Worker *   04/02/97  aliu        Creation.
15*0e209d39SAndroid Build Coastguard Worker *   04/07/99  srl         rewrite - C interface, multiple mutices
16*0e209d39SAndroid Build Coastguard Worker *   05/13/99  stephen     Changed to umutex (from cmutex)
17*0e209d39SAndroid Build Coastguard Worker ******************************************************************************
18*0e209d39SAndroid Build Coastguard Worker */
19*0e209d39SAndroid Build Coastguard Worker 
20*0e209d39SAndroid Build Coastguard Worker #ifndef UMUTEX_H
21*0e209d39SAndroid Build Coastguard Worker #define UMUTEX_H
22*0e209d39SAndroid Build Coastguard Worker 
23*0e209d39SAndroid Build Coastguard Worker #include <atomic>
24*0e209d39SAndroid Build Coastguard Worker #include <condition_variable>
25*0e209d39SAndroid Build Coastguard Worker #include <mutex>
26*0e209d39SAndroid Build Coastguard Worker #include <type_traits>
27*0e209d39SAndroid Build Coastguard Worker 
28*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h"
29*0e209d39SAndroid Build Coastguard Worker #include "unicode/uclean.h"
30*0e209d39SAndroid Build Coastguard Worker #include "unicode/uobject.h"
31*0e209d39SAndroid Build Coastguard Worker 
32*0e209d39SAndroid Build Coastguard Worker #include "putilimp.h"
33*0e209d39SAndroid Build Coastguard Worker 
34*0e209d39SAndroid Build Coastguard Worker #if defined(U_USER_ATOMICS_H) || defined(U_USER_MUTEX_H)
35*0e209d39SAndroid Build Coastguard Worker // Support for including an alternate implementation of atomic & mutex operations has been withdrawn.
36*0e209d39SAndroid Build Coastguard Worker // See issue ICU-20185.
37*0e209d39SAndroid Build Coastguard Worker #error U_USER_ATOMICS and U_USER_MUTEX_H are not supported
38*0e209d39SAndroid Build Coastguard Worker #endif
39*0e209d39SAndroid Build Coastguard Worker 
40*0e209d39SAndroid Build Coastguard Worker // Export an explicit template instantiation of std::atomic<int32_t>.
41*0e209d39SAndroid Build Coastguard Worker // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
42*0e209d39SAndroid Build Coastguard Worker // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
43*0e209d39SAndroid Build Coastguard Worker //
44*0e209d39SAndroid Build Coastguard Worker // Similar story for std::atomic<std::mutex *>, and the exported UMutex class.
45*0e209d39SAndroid Build Coastguard Worker #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
46*0e209d39SAndroid Build Coastguard Worker #if defined(__clang__) || defined(_MSC_VER)
47*0e209d39SAndroid Build Coastguard Worker   #if defined(__clang__)
48*0e209d39SAndroid Build Coastguard Worker     // Suppress the warning that the explicit instantiation after explicit specialization has no effect.
49*0e209d39SAndroid Build Coastguard Worker     #pragma clang diagnostic push
50*0e209d39SAndroid Build Coastguard Worker     #pragma clang diagnostic ignored "-Winstantiation-after-specialization"
51*0e209d39SAndroid Build Coastguard Worker   #endif
52*0e209d39SAndroid Build Coastguard Worker template struct U_COMMON_API std::atomic<int32_t>;
53*0e209d39SAndroid Build Coastguard Worker template struct U_COMMON_API std::atomic<std::mutex *>;
54*0e209d39SAndroid Build Coastguard Worker   #if defined(__clang__)
55*0e209d39SAndroid Build Coastguard Worker     #pragma clang diagnostic pop
56*0e209d39SAndroid Build Coastguard Worker   #endif
57*0e209d39SAndroid Build Coastguard Worker #elif defined(__GNUC__)
58*0e209d39SAndroid Build Coastguard Worker // For GCC this class is already exported/visible, so no need for U_COMMON_API.
59*0e209d39SAndroid Build Coastguard Worker template struct std::atomic<int32_t>;
60*0e209d39SAndroid Build Coastguard Worker template struct std::atomic<std::mutex *>;
61*0e209d39SAndroid Build Coastguard Worker #endif
62*0e209d39SAndroid Build Coastguard Worker #endif
63*0e209d39SAndroid Build Coastguard Worker 
64*0e209d39SAndroid Build Coastguard Worker 
65*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN
66*0e209d39SAndroid Build Coastguard Worker 
67*0e209d39SAndroid Build Coastguard Worker /****************************************************************************
68*0e209d39SAndroid Build Coastguard Worker  *
69*0e209d39SAndroid Build Coastguard Worker  *   Low Level Atomic Operations, ICU wrappers for.
70*0e209d39SAndroid Build Coastguard Worker  *
71*0e209d39SAndroid Build Coastguard Worker  ****************************************************************************/
72*0e209d39SAndroid Build Coastguard Worker 
73*0e209d39SAndroid Build Coastguard Worker typedef std::atomic<int32_t> u_atomic_int32_t;
74*0e209d39SAndroid Build Coastguard Worker 
75*0e209d39SAndroid Build Coastguard Worker inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
76*0e209d39SAndroid Build Coastguard Worker     return var.load(std::memory_order_acquire);
77*0e209d39SAndroid Build Coastguard Worker }
78*0e209d39SAndroid Build Coastguard Worker 
79*0e209d39SAndroid Build Coastguard Worker inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
80*0e209d39SAndroid Build Coastguard Worker     var.store(val, std::memory_order_release);
81*0e209d39SAndroid Build Coastguard Worker }
82*0e209d39SAndroid Build Coastguard Worker 
83*0e209d39SAndroid Build Coastguard Worker inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
84*0e209d39SAndroid Build Coastguard Worker     return var->fetch_add(1) + 1;
85*0e209d39SAndroid Build Coastguard Worker }
86*0e209d39SAndroid Build Coastguard Worker 
87*0e209d39SAndroid Build Coastguard Worker inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
88*0e209d39SAndroid Build Coastguard Worker     return var->fetch_sub(1) - 1;
89*0e209d39SAndroid Build Coastguard Worker }
90*0e209d39SAndroid Build Coastguard Worker 
91*0e209d39SAndroid Build Coastguard Worker 
92*0e209d39SAndroid Build Coastguard Worker /*************************************************************************************************
93*0e209d39SAndroid Build Coastguard Worker  *
94*0e209d39SAndroid Build Coastguard Worker  *  UInitOnce Definitions.
95*0e209d39SAndroid Build Coastguard Worker  *
96*0e209d39SAndroid Build Coastguard Worker  *************************************************************************************************/
97*0e209d39SAndroid Build Coastguard Worker 
98*0e209d39SAndroid Build Coastguard Worker struct U_COMMON_API UInitOnce {
99*0e209d39SAndroid Build Coastguard Worker     u_atomic_int32_t   fState {0};
100*0e209d39SAndroid Build Coastguard Worker     UErrorCode       fErrCode {U_ZERO_ERROR};
101*0e209d39SAndroid Build Coastguard Worker     void reset() {fState = 0;}
102*0e209d39SAndroid Build Coastguard Worker     UBool isReset() {return umtx_loadAcquire(fState) == 0;}
103*0e209d39SAndroid Build Coastguard Worker // Note: isReset() is used by service registration code.
104*0e209d39SAndroid Build Coastguard Worker //                 Thread safety of this usage needs review.
105*0e209d39SAndroid Build Coastguard Worker };
106*0e209d39SAndroid Build Coastguard Worker 
107*0e209d39SAndroid Build Coastguard Worker U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
108*0e209d39SAndroid Build Coastguard Worker U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
109*0e209d39SAndroid Build Coastguard Worker 
110*0e209d39SAndroid Build Coastguard Worker template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
111*0e209d39SAndroid Build Coastguard Worker     if (umtx_loadAcquire(uio.fState) == 2) {
112*0e209d39SAndroid Build Coastguard Worker         return;
113*0e209d39SAndroid Build Coastguard Worker     }
114*0e209d39SAndroid Build Coastguard Worker     if (umtx_initImplPreInit(uio)) {
115*0e209d39SAndroid Build Coastguard Worker         (obj->*fp)();
116*0e209d39SAndroid Build Coastguard Worker         umtx_initImplPostInit(uio);
117*0e209d39SAndroid Build Coastguard Worker     }
118*0e209d39SAndroid Build Coastguard Worker }
119*0e209d39SAndroid Build Coastguard Worker 
120*0e209d39SAndroid Build Coastguard Worker 
121*0e209d39SAndroid Build Coastguard Worker // umtx_initOnce variant for plain functions, or static class functions.
122*0e209d39SAndroid Build Coastguard Worker //               No context parameter.
123*0e209d39SAndroid Build Coastguard Worker inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
124*0e209d39SAndroid Build Coastguard Worker     if (umtx_loadAcquire(uio.fState) == 2) {
125*0e209d39SAndroid Build Coastguard Worker         return;
126*0e209d39SAndroid Build Coastguard Worker     }
127*0e209d39SAndroid Build Coastguard Worker     if (umtx_initImplPreInit(uio)) {
128*0e209d39SAndroid Build Coastguard Worker         (*fp)();
129*0e209d39SAndroid Build Coastguard Worker         umtx_initImplPostInit(uio);
130*0e209d39SAndroid Build Coastguard Worker     }
131*0e209d39SAndroid Build Coastguard Worker }
132*0e209d39SAndroid Build Coastguard Worker 
133*0e209d39SAndroid Build Coastguard Worker // umtx_initOnce variant for plain functions, or static class functions.
134*0e209d39SAndroid Build Coastguard Worker //               With ErrorCode, No context parameter.
135*0e209d39SAndroid Build Coastguard Worker inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
136*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(errCode)) {
137*0e209d39SAndroid Build Coastguard Worker         return;
138*0e209d39SAndroid Build Coastguard Worker     }
139*0e209d39SAndroid Build Coastguard Worker     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
140*0e209d39SAndroid Build Coastguard Worker         // We run the initialization.
141*0e209d39SAndroid Build Coastguard Worker         (*fp)(errCode);
142*0e209d39SAndroid Build Coastguard Worker         uio.fErrCode = errCode;
143*0e209d39SAndroid Build Coastguard Worker         umtx_initImplPostInit(uio);
144*0e209d39SAndroid Build Coastguard Worker     } else {
145*0e209d39SAndroid Build Coastguard Worker         // Someone else already ran the initialization.
146*0e209d39SAndroid Build Coastguard Worker         if (U_FAILURE(uio.fErrCode)) {
147*0e209d39SAndroid Build Coastguard Worker             errCode = uio.fErrCode;
148*0e209d39SAndroid Build Coastguard Worker         }
149*0e209d39SAndroid Build Coastguard Worker     }
150*0e209d39SAndroid Build Coastguard Worker }
151*0e209d39SAndroid Build Coastguard Worker 
152*0e209d39SAndroid Build Coastguard Worker // umtx_initOnce variant for plain functions, or static class functions,
153*0e209d39SAndroid Build Coastguard Worker //               with a context parameter.
154*0e209d39SAndroid Build Coastguard Worker template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
155*0e209d39SAndroid Build Coastguard Worker     if (umtx_loadAcquire(uio.fState) == 2) {
156*0e209d39SAndroid Build Coastguard Worker         return;
157*0e209d39SAndroid Build Coastguard Worker     }
158*0e209d39SAndroid Build Coastguard Worker     if (umtx_initImplPreInit(uio)) {
159*0e209d39SAndroid Build Coastguard Worker         (*fp)(context);
160*0e209d39SAndroid Build Coastguard Worker         umtx_initImplPostInit(uio);
161*0e209d39SAndroid Build Coastguard Worker     }
162*0e209d39SAndroid Build Coastguard Worker }
163*0e209d39SAndroid Build Coastguard Worker 
164*0e209d39SAndroid Build Coastguard Worker // umtx_initOnce variant for plain functions, or static class functions,
165*0e209d39SAndroid Build Coastguard Worker //               with a context parameter and an error code.
166*0e209d39SAndroid Build Coastguard Worker template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
167*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(errCode)) {
168*0e209d39SAndroid Build Coastguard Worker         return;
169*0e209d39SAndroid Build Coastguard Worker     }
170*0e209d39SAndroid Build Coastguard Worker     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
171*0e209d39SAndroid Build Coastguard Worker         // We run the initialization.
172*0e209d39SAndroid Build Coastguard Worker         (*fp)(context, errCode);
173*0e209d39SAndroid Build Coastguard Worker         uio.fErrCode = errCode;
174*0e209d39SAndroid Build Coastguard Worker         umtx_initImplPostInit(uio);
175*0e209d39SAndroid Build Coastguard Worker     } else {
176*0e209d39SAndroid Build Coastguard Worker         // Someone else already ran the initialization.
177*0e209d39SAndroid Build Coastguard Worker         if (U_FAILURE(uio.fErrCode)) {
178*0e209d39SAndroid Build Coastguard Worker             errCode = uio.fErrCode;
179*0e209d39SAndroid Build Coastguard Worker         }
180*0e209d39SAndroid Build Coastguard Worker     }
181*0e209d39SAndroid Build Coastguard Worker }
182*0e209d39SAndroid Build Coastguard Worker 
183*0e209d39SAndroid Build Coastguard Worker // UMutex should be constexpr-constructible, so that no initialization code
184*0e209d39SAndroid Build Coastguard Worker // is run during startup.
185*0e209d39SAndroid Build Coastguard Worker // This works on all C++ libraries except MS VS before VS2019.
186*0e209d39SAndroid Build Coastguard Worker #if (defined(_CPPLIB_VER) && !defined(_MSVC_STL_VERSION)) || \
187*0e209d39SAndroid Build Coastguard Worker     (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142)
188*0e209d39SAndroid Build Coastguard Worker     // (VS std lib older than VS2017) || (VS std lib version < VS2019)
189*0e209d39SAndroid Build Coastguard Worker #   define UMUTEX_CONSTEXPR
190*0e209d39SAndroid Build Coastguard Worker #else
191*0e209d39SAndroid Build Coastguard Worker #   define UMUTEX_CONSTEXPR constexpr
192*0e209d39SAndroid Build Coastguard Worker #endif
193*0e209d39SAndroid Build Coastguard Worker 
194*0e209d39SAndroid Build Coastguard Worker /**
195*0e209d39SAndroid Build Coastguard Worker  * UMutex - ICU Mutex class.
196*0e209d39SAndroid Build Coastguard Worker  *
197*0e209d39SAndroid Build Coastguard Worker  * This is the preferred Mutex class for use within ICU implementation code.
198*0e209d39SAndroid Build Coastguard Worker  * It is a thin wrapper over C++ std::mutex, with these additions:
199*0e209d39SAndroid Build Coastguard Worker  *    - Static instances are safe, not triggering static construction or destruction,
200*0e209d39SAndroid Build Coastguard Worker  *      and the associated order of construction or destruction issues.
201*0e209d39SAndroid Build Coastguard Worker  *    - Plumbed into u_cleanup() for destructing the underlying std::mutex,
202*0e209d39SAndroid Build Coastguard Worker  *      which frees any OS level resources they may be holding.
203*0e209d39SAndroid Build Coastguard Worker  *
204*0e209d39SAndroid Build Coastguard Worker  * Limitations:
205*0e209d39SAndroid Build Coastguard Worker  *    - Static or global instances only. Cannot be heap allocated. Cannot appear as a
206*0e209d39SAndroid Build Coastguard Worker  *      member of another class.
207*0e209d39SAndroid Build Coastguard Worker  *    - No condition variables or other advanced features. If needed, you will need to use
208*0e209d39SAndroid Build Coastguard Worker  *      std::mutex and std::condition_variable directly. For an example, see unifiedcache.cpp
209*0e209d39SAndroid Build Coastguard Worker  *
210*0e209d39SAndroid Build Coastguard Worker  * Typical Usage:
211*0e209d39SAndroid Build Coastguard Worker  *    static UMutex myMutex;
212*0e209d39SAndroid Build Coastguard Worker  *
213*0e209d39SAndroid Build Coastguard Worker  *    {
214*0e209d39SAndroid Build Coastguard Worker  *       Mutex lock(myMutex);
215*0e209d39SAndroid Build Coastguard Worker  *       ...    // Do stuff that is protected by myMutex;
216*0e209d39SAndroid Build Coastguard Worker  *    }         // myMutex is released when lock goes out of scope.
217*0e209d39SAndroid Build Coastguard Worker  */
218*0e209d39SAndroid Build Coastguard Worker 
219*0e209d39SAndroid Build Coastguard Worker class U_COMMON_API UMutex {
220*0e209d39SAndroid Build Coastguard Worker public:
221*0e209d39SAndroid Build Coastguard Worker     UMUTEX_CONSTEXPR UMutex() {}
222*0e209d39SAndroid Build Coastguard Worker     ~UMutex() = default;
223*0e209d39SAndroid Build Coastguard Worker 
224*0e209d39SAndroid Build Coastguard Worker     UMutex(const UMutex &other) = delete;
225*0e209d39SAndroid Build Coastguard Worker     UMutex &operator =(const UMutex &other) = delete;
226*0e209d39SAndroid Build Coastguard Worker     void *operator new(size_t) = delete;
227*0e209d39SAndroid Build Coastguard Worker 
228*0e209d39SAndroid Build Coastguard Worker     // requirements for C++ BasicLockable, allows UMutex to work with std::lock_guard
229*0e209d39SAndroid Build Coastguard Worker     void lock() {
230*0e209d39SAndroid Build Coastguard Worker         std::mutex *m = fMutex.load(std::memory_order_acquire);
231*0e209d39SAndroid Build Coastguard Worker         if (m == nullptr) { m = getMutex(); }
232*0e209d39SAndroid Build Coastguard Worker         m->lock();
233*0e209d39SAndroid Build Coastguard Worker     }
234*0e209d39SAndroid Build Coastguard Worker     void unlock() { fMutex.load(std::memory_order_relaxed)->unlock(); }
235*0e209d39SAndroid Build Coastguard Worker 
236*0e209d39SAndroid Build Coastguard Worker     static void cleanup();
237*0e209d39SAndroid Build Coastguard Worker 
238*0e209d39SAndroid Build Coastguard Worker private:
239*0e209d39SAndroid Build Coastguard Worker     alignas(std::mutex) char fStorage[sizeof(std::mutex)] {};
240*0e209d39SAndroid Build Coastguard Worker     std::atomic<std::mutex *> fMutex { nullptr };
241*0e209d39SAndroid Build Coastguard Worker 
242*0e209d39SAndroid Build Coastguard Worker     /** All initialized UMutexes are kept in a linked list, so that they can be found,
243*0e209d39SAndroid Build Coastguard Worker      * and the underlying std::mutex destructed, by u_cleanup().
244*0e209d39SAndroid Build Coastguard Worker      */
245*0e209d39SAndroid Build Coastguard Worker     UMutex *fListLink { nullptr };
246*0e209d39SAndroid Build Coastguard Worker     static UMutex *gListHead;
247*0e209d39SAndroid Build Coastguard Worker 
248*0e209d39SAndroid Build Coastguard Worker     /** Out-of-line function to lazily initialize a UMutex on first use.
249*0e209d39SAndroid Build Coastguard Worker      * Initial fast check is inline, in lock().  The returned value may never
250*0e209d39SAndroid Build Coastguard Worker      * be nullptr.
251*0e209d39SAndroid Build Coastguard Worker      */
252*0e209d39SAndroid Build Coastguard Worker     std::mutex *getMutex();
253*0e209d39SAndroid Build Coastguard Worker };
254*0e209d39SAndroid Build Coastguard Worker 
255*0e209d39SAndroid Build Coastguard Worker 
256*0e209d39SAndroid Build Coastguard Worker /* Lock a mutex.
257*0e209d39SAndroid Build Coastguard Worker  * @param mutex The given mutex to be locked.  Pass NULL to specify
258*0e209d39SAndroid Build Coastguard Worker  *              the global ICU mutex.  Recursive locks are an error
259*0e209d39SAndroid Build Coastguard Worker  *              and may cause a deadlock on some platforms.
260*0e209d39SAndroid Build Coastguard Worker  */
261*0e209d39SAndroid Build Coastguard Worker U_CAPI void U_EXPORT2 umtx_lock(UMutex* mutex);
262*0e209d39SAndroid Build Coastguard Worker 
263*0e209d39SAndroid Build Coastguard Worker /* Unlock a mutex.
264*0e209d39SAndroid Build Coastguard Worker  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
265*0e209d39SAndroid Build Coastguard Worker  *              the global ICU mutex.
266*0e209d39SAndroid Build Coastguard Worker  */
267*0e209d39SAndroid Build Coastguard Worker U_CAPI void U_EXPORT2 umtx_unlock (UMutex* mutex);
268*0e209d39SAndroid Build Coastguard Worker 
269*0e209d39SAndroid Build Coastguard Worker 
270*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END
271*0e209d39SAndroid Build Coastguard Worker 
272*0e209d39SAndroid Build Coastguard Worker #endif /* UMUTEX_H */
273*0e209d39SAndroid Build Coastguard Worker /*eof*/
274