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