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