Home | History | Annotate | Download | only in common
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 **********************************************************************
      5 *   Copyright (C) 1997-2015, International Business Machines
      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 
     23 #include "unicode/utypes.h"
     24 #include "unicode/uclean.h"
     25 #include "putilimp.h"
     26 
     27 
     28 
     29 // Forward Declarations. UMutex is not in the ICU namespace (yet) because
     30 //                       there are some remaining references from plain C.
     31 struct UMutex;
     32 struct UConditionVar;
     33 
     34 U_NAMESPACE_BEGIN
     35 struct UInitOnce;
     36 U_NAMESPACE_END
     37 
     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)
     41 
     42 /****************************************************************************
     43  *
     44  *   Low Level Atomic Operations.
     45  *      Compiler dependent. Not operating system dependent.
     46  *
     47  ****************************************************************************/
     48 #if defined (U_USER_ATOMICS_H)
     49 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
     50 
     51 #elif U_HAVE_STD_ATOMICS
     52 
     53 //  C++11 atomics are available.
     54 
     55 #include <atomic>
     56 
     57 // Export an explicit template instantiation of std::atomic<int32_t>.
     58 // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
     59 // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
     60 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
     61   #if defined(__clang__)
     62   // Suppress the warning that the explicit instantiation after explicit specialization has no effect.
     63   #pragma clang diagnostic push
     64   #pragma clang diagnostic ignored "-Winstantiation-after-specialization"
     65   #endif
     66 template struct U_COMMON_API std::atomic<int32_t>;
     67   #if defined(__clang__)
     68   #pragma clang diagnostic pop
     69   #endif
     70 #endif
     71 
     72 U_NAMESPACE_BEGIN
     73 
     74 typedef std::atomic<int32_t> u_atomic_int32_t;
     75 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
     76 
     77 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
     78     return var.load(std::memory_order_acquire);
     79 }
     80 
     81 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
     82     var.store(val, std::memory_order_release);
     83 }
     84 
     85 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
     86     return var->fetch_add(1) + 1;
     87 }
     88 
     89 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
     90     return var->fetch_sub(1) - 1;
     91 }
     92 U_NAMESPACE_END
     93 
     94 #elif U_PLATFORM_HAS_WIN32_API
     95 
     96 // MSVC compiler. Reads and writes of volatile variables have
     97 //                acquire and release memory semantics, respectively.
     98 //                This is a Microsoft extension, not standard C++ behavior.
     99 //
    100 //   Update:      can't use this because of MinGW, built with gcc.
    101 //                Original plan was to use gcc atomics for MinGW, but they
    102 //                aren't supported, so we fold MinGW into this path.
    103 
    104 #ifndef WIN32_LEAN_AND_MEAN
    105 # define WIN32_LEAN_AND_MEAN
    106 #endif
    107 # define VC_EXTRALEAN
    108 # define NOUSER
    109 # define NOSERVICE
    110 # define NOIME
    111 # define NOMCX
    112 # ifndef NOMINMAX
    113 # define NOMINMAX
    114 # endif
    115 # include <windows.h>
    116 
    117 U_NAMESPACE_BEGIN
    118 typedef volatile LONG u_atomic_int32_t;
    119 #define ATOMIC_INT32_T_INITIALIZER(val) val
    120 
    121 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    122     return InterlockedCompareExchange(&var, 0, 0);
    123 }
    124 
    125 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    126     InterlockedExchange(&var, val);
    127 }
    128 
    129 
    130 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
    131     return InterlockedIncrement(var);
    132 }
    133 
    134 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
    135     return InterlockedDecrement(var);
    136 }
    137 U_NAMESPACE_END
    138 
    139 
    140 #elif U_HAVE_CLANG_ATOMICS
    141 /*
    142  *  Clang __c11 atomic built-ins
    143  */
    144 
    145 U_NAMESPACE_BEGIN
    146 typedef _Atomic(int32_t) u_atomic_int32_t;
    147 #define ATOMIC_INT32_T_INITIALIZER(val) val
    148 
    149 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    150      return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
    151 }
    152 
    153 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    154    return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
    155 }
    156 
    157 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
    158     return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
    159 }
    160 
    161 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
    162     return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
    163 }
    164 U_NAMESPACE_END
    165 
    166 
    167 #elif U_HAVE_GCC_ATOMICS
    168 /*
    169  * gcc atomic ops. These are available on several other compilers as well.
    170  */
    171 
    172 U_NAMESPACE_BEGIN
    173 typedef int32_t u_atomic_int32_t;
    174 #define ATOMIC_INT32_T_INITIALIZER(val) val
    175 
    176 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    177     int32_t val = var;
    178     __sync_synchronize();
    179     return val;
    180 }
    181 
    182 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    183     __sync_synchronize();
    184     var = val;
    185 }
    186 
    187 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
    188    return __sync_add_and_fetch(p, 1);
    189 }
    190 
    191 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
    192    return __sync_sub_and_fetch(p, 1);
    193 }
    194 U_NAMESPACE_END
    195 
    196 #else
    197 
    198 /*
    199  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
    200  *                   Slow but correct.
    201  */
    202 
    203 #define U_NO_PLATFORM_ATOMICS
    204 
    205 U_NAMESPACE_BEGIN
    206 typedef int32_t u_atomic_int32_t;
    207 #define ATOMIC_INT32_T_INITIALIZER(val) val
    208 
    209 U_COMMON_API int32_t U_EXPORT2
    210 umtx_loadAcquire(u_atomic_int32_t &var);
    211 
    212 U_COMMON_API void U_EXPORT2
    213 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
    214 
    215 U_COMMON_API int32_t U_EXPORT2
    216 umtx_atomic_inc(u_atomic_int32_t *p);
    217 
    218 U_COMMON_API int32_t U_EXPORT2
    219 umtx_atomic_dec(u_atomic_int32_t *p);
    220 
    221 U_NAMESPACE_END
    222 
    223 #endif  /* Low Level Atomic Ops Platform Chain */
    224 
    225 
    226 
    227 /*************************************************************************************************
    228  *
    229  *  UInitOnce Definitions.
    230  *     These are platform neutral.
    231  *
    232  *************************************************************************************************/
    233 
    234 U_NAMESPACE_BEGIN
    235 
    236 struct UInitOnce {
    237     u_atomic_int32_t   fState;
    238     UErrorCode       fErrCode;
    239     void reset() {fState = 0;};
    240     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
    241 // Note: isReset() is used by service registration code.
    242 //                 Thread safety of this usage needs review.
    243 };
    244 
    245 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
    246 
    247 
    248 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
    249 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
    250 
    251 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
    252     if (umtx_loadAcquire(uio.fState) == 2) {
    253         return;
    254     }
    255     if (umtx_initImplPreInit(uio)) {
    256         (obj->*fp)();
    257         umtx_initImplPostInit(uio);
    258     }
    259 }
    260 
    261 
    262 // umtx_initOnce variant for plain functions, or static class functions.
    263 //               No context parameter.
    264 inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
    265     if (umtx_loadAcquire(uio.fState) == 2) {
    266         return;
    267     }
    268     if (umtx_initImplPreInit(uio)) {
    269         (*fp)();
    270         umtx_initImplPostInit(uio);
    271     }
    272 }
    273 
    274 // umtx_initOnce variant for plain functions, or static class functions.
    275 //               With ErrorCode, No context parameter.
    276 inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
    277     if (U_FAILURE(errCode)) {
    278         return;
    279     }
    280     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
    281         // We run the initialization.
    282         (*fp)(errCode);
    283         uio.fErrCode = errCode;
    284         umtx_initImplPostInit(uio);
    285     } else {
    286         // Someone else already ran the initialization.
    287         if (U_FAILURE(uio.fErrCode)) {
    288             errCode = uio.fErrCode;
    289         }
    290     }
    291 }
    292 
    293 // umtx_initOnce variant for plain functions, or static class functions,
    294 //               with a context parameter.
    295 template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
    296     if (umtx_loadAcquire(uio.fState) == 2) {
    297         return;
    298     }
    299     if (umtx_initImplPreInit(uio)) {
    300         (*fp)(context);
    301         umtx_initImplPostInit(uio);
    302     }
    303 }
    304 
    305 // umtx_initOnce variant for plain functions, or static class functions,
    306 //               with a context parameter and an error code.
    307 template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
    308     if (U_FAILURE(errCode)) {
    309         return;
    310     }
    311     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
    312         // We run the initialization.
    313         (*fp)(context, errCode);
    314         uio.fErrCode = errCode;
    315         umtx_initImplPostInit(uio);
    316     } else {
    317         // Someone else already ran the initialization.
    318         if (U_FAILURE(uio.fErrCode)) {
    319             errCode = uio.fErrCode;
    320         }
    321     }
    322 }
    323 
    324 U_NAMESPACE_END
    325 
    326 
    327 
    328 /*************************************************************************************************
    329  *
    330  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
    331  *         TODO:  Add a C++11 version.
    332  *                Need to convert all mutex using files to C++ first.
    333  *
    334  *************************************************************************************************/
    335 
    336 #if defined(U_USER_MUTEX_H)
    337 // #include "U_USER_MUTEX_H"
    338 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
    339 
    340 #elif U_PLATFORM_USES_ONLY_WIN32_API
    341 
    342 /* For CRITICAL_SECTION */
    343 
    344 /*
    345  *   Note: there is an earlier include of windows.h in this file, but it is in
    346  *         different conditionals.
    347  *         This one is needed if we are using C++11 for atomic ops, but
    348  *         win32 APIs for Critical Sections.
    349  */
    350 
    351 #ifndef WIN32_LEAN_AND_MEAN
    352 # define WIN32_LEAN_AND_MEAN
    353 #endif
    354 # define VC_EXTRALEAN
    355 # define NOUSER
    356 # define NOSERVICE
    357 # define NOIME
    358 # define NOMCX
    359 # ifndef NOMINMAX
    360 # define NOMINMAX
    361 # endif
    362 # include <windows.h>
    363 
    364 
    365 typedef struct UMutex {
    366     icu::UInitOnce    fInitOnce;
    367     CRITICAL_SECTION  fCS;
    368 } UMutex;
    369 
    370 /* Initializer for a static UMUTEX. Deliberately contains no value for the
    371  *  CRITICAL_SECTION.
    372  */
    373 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
    374 
    375 struct UConditionVar {
    376     HANDLE           fEntryGate;
    377     HANDLE           fExitGate;
    378     int32_t          fWaitCount;
    379 };
    380 
    381 #define U_CONDITION_INITIALIZER {NULL, NULL, 0}
    382 
    383 
    384 
    385 #elif U_PLATFORM_IMPLEMENTS_POSIX
    386 
    387 /*
    388  *  POSIX platform
    389  */
    390 
    391 #include <pthread.h>
    392 
    393 struct UMutex {
    394     pthread_mutex_t  fMutex;
    395 };
    396 typedef struct UMutex UMutex;
    397 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
    398 
    399 struct UConditionVar {
    400     pthread_cond_t   fCondition;
    401 };
    402 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
    403 
    404 #else
    405 
    406 /*
    407  *  Unknown platform type.
    408  *      This is an error condition. ICU requires mutexes.
    409  */
    410 
    411 #error Unknown Platform.
    412 
    413 #endif
    414 
    415 
    416 
    417 /**************************************************************************************
    418  *
    419  *  Mutex Implementation function declarations.
    420  *     Declarations are platform neutral.
    421  *     Implementations, in umutex.cpp, are platform specific.
    422  *
    423  ************************************************************************************/
    424 
    425 /* Lock a mutex.
    426  * @param mutex The given mutex to be locked.  Pass NULL to specify
    427  *              the global ICU mutex.  Recursive locks are an error
    428  *              and may cause a deadlock on some platforms.
    429  */
    430 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
    431 
    432 /* Unlock a mutex.
    433  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
    434  *              the global ICU mutex.
    435  */
    436 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
    437 
    438 /*
    439  * Wait on a condition variable.
    440  * The calling thread will unlock the mutex and wait on the condition variable.
    441  * The mutex must be locked by the calling thread when invoking this function.
    442  *
    443  * @param cond the condition variable to wait on.
    444  * @param mutex the associated mutex.
    445  */
    446 
    447 U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
    448 
    449 
    450 /*
    451  * Broadcast wakeup of all threads waiting on a Condition.
    452  * The associated mutex must be locked by the calling thread when calling
    453  * this function; this is a temporary ICU restriction.
    454  *
    455  * @param cond the condition variable.
    456  */
    457 U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
    458 
    459 /*
    460  * Signal a condition variable, waking up one waiting thread.
    461  * CAUTION: Do not use. Place holder only. Not implemented for Windows.
    462  */
    463 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
    464 
    465 #endif /* UMUTEX_H */
    466 /*eof*/
    467