Home | History | Annotate | Download | only in common
      1 /*
      2 **********************************************************************
      3 *   Copyright (C) 1997-2013, International Business Machines
      4 *   Corporation and others.  All Rights Reserved.
      5 **********************************************************************
      6 *
      7 * File UMUTEX.H
      8 *
      9 * Modification History:
     10 *
     11 *   Date        Name        Description
     12 *   04/02/97  aliu        Creation.
     13 *   04/07/99  srl         rewrite - C interface, multiple mutices
     14 *   05/13/99  stephen     Changed to umutex (from cmutex)
     15 ******************************************************************************
     16 */
     17 
     18 #ifndef UMUTEX_H
     19 #define UMUTEX_H
     20 
     21 #include "unicode/utypes.h"
     22 #include "unicode/uclean.h"
     23 #include "putilimp.h"
     24 
     25 
     26 
     27 // Forward Declarations. UMutex is not in the ICU namespace (yet) because
     28 //                       there are some remaining references from plain C.
     29 struct UMutex;
     30 
     31 U_NAMESPACE_BEGIN
     32 struct UInitOnce;
     33 U_NAMESPACE_END
     34 
     35 // Stringify macros, to allow #include of user supplied atomic & mutex files.
     36 #define U_MUTEX_STR(s) #s
     37 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
     38 
     39 /****************************************************************************
     40  *
     41  *   Low Level Atomic Operations.
     42  *      Compiler dependent. Not operating system dependent.
     43  *
     44  ****************************************************************************/
     45 #if defined (U_USER_ATOMICS_H)
     46 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
     47 
     48 #elif U_HAVE_STD_ATOMICS
     49 
     50 //  C++11 atomics are available.
     51 
     52 #include <atomic>
     53 
     54 U_NAMESPACE_BEGIN
     55 
     56 typedef std::atomic<int32_t> u_atomic_int32_t;
     57 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
     58 
     59 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
     60     return var.load(std::memory_order_acquire);
     61 }
     62 
     63 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
     64     var.store(val, std::memory_order_release);
     65 }
     66 
     67 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
     68     return var->fetch_add(1) + 1;
     69 }
     70 
     71 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
     72     return var->fetch_sub(1) - 1;
     73 }
     74 U_NAMESPACE_END
     75 
     76 #elif U_PLATFORM_HAS_WIN32_API
     77 
     78 // MSVC compiler. Reads and writes of volatile variables have
     79 //                acquire and release memory semantics, respectively.
     80 //                This is a Microsoft extension, not standard C++ behavior.
     81 //
     82 //   Update:      can't use this because of MinGW, built with gcc.
     83 //                Original plan was to use gcc atomics for MinGW, but they
     84 //                aren't supported, so we fold MinGW into this path.
     85 
     86 # define WIN32_LEAN_AND_MEAN
     87 # define VC_EXTRALEAN
     88 # define NOUSER
     89 # define NOSERVICE
     90 # define NOIME
     91 # define NOMCX
     92 # ifndef NOMINMAX
     93 # define NOMINMAX
     94 # endif
     95 # include <windows.h>
     96 U_NAMESPACE_BEGIN
     97 typedef volatile LONG u_atomic_int32_t;
     98 #define ATOMIC_INT32_T_INITIALIZER(val) val
     99 
    100 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    101     return InterlockedCompareExchange(&var, 0, 0);
    102 }
    103 
    104 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    105     InterlockedExchange(&var, val);
    106 }
    107 
    108 
    109 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
    110     return InterlockedIncrement(var);
    111 }
    112 
    113 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
    114     return InterlockedDecrement(var);
    115 }
    116 U_NAMESPACE_END
    117 
    118 #elif U_HAVE_GCC_ATOMICS
    119 /*
    120  * gcc atomic ops. These are available on several other compilers as well.
    121  */
    122 
    123 U_NAMESPACE_BEGIN
    124 typedef int32_t u_atomic_int32_t;
    125 #define ATOMIC_INT32_T_INITIALIZER(val) val
    126 
    127 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    128     int32_t val = var;
    129     __sync_synchronize();
    130     return val;
    131 }
    132 
    133 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    134     __sync_synchronize();
    135     var = val;
    136 }
    137 
    138 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
    139    return __sync_add_and_fetch(p, 1);
    140 }
    141 
    142 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
    143    return __sync_sub_and_fetch(p, 1);
    144 }
    145 U_NAMESPACE_END
    146 
    147 #else
    148 
    149 /*
    150  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
    151  *                   Slow but correct.
    152  */
    153 
    154 #define U_NO_PLATFORM_ATOMICS
    155 
    156 U_NAMESPACE_BEGIN
    157 typedef int32_t u_atomic_int32_t;
    158 #define ATOMIC_INT32_T_INITIALIZER(val) val
    159 
    160 U_COMMON_API int32_t U_EXPORT2
    161 umtx_loadAcquire(u_atomic_int32_t &var);
    162 
    163 U_COMMON_API void U_EXPORT2
    164 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
    165 
    166 U_COMMON_API int32_t U_EXPORT2
    167 umtx_atomic_inc(u_atomic_int32_t *p);
    168 
    169 U_COMMON_API int32_t U_EXPORT2
    170 umtx_atomic_dec(u_atomic_int32_t *p);
    171 
    172 U_NAMESPACE_END
    173 
    174 #endif  /* Low Level Atomic Ops Platfrom Chain */
    175 
    176 
    177 
    178 /*************************************************************************************************
    179  *
    180  *  UInitOnce Definitions.
    181  *     These are platform neutral.
    182  *
    183  *************************************************************************************************/
    184 
    185 U_NAMESPACE_BEGIN
    186 
    187 struct UInitOnce {
    188     u_atomic_int32_t   fState;
    189     UErrorCode       fErrCode;
    190     void reset() {fState = 0;};
    191     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
    192 // Note: isReset() is used by service registration code.
    193 //                 Thread safety of this usage needs review.
    194 };
    195 
    196 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
    197 
    198 
    199 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
    200 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
    201 
    202 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
    203     if (umtx_loadAcquire(uio.fState) == 2) {
    204         return;
    205     }
    206     if (umtx_initImplPreInit(uio)) {
    207         (obj->*fp)();
    208         umtx_initImplPostInit(uio);
    209     }
    210 }
    211 
    212 
    213 // umtx_initOnce variant for plain functions, or static class functions.
    214 //               No context parameter.
    215 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
    216     if (umtx_loadAcquire(uio.fState) == 2) {
    217         return;
    218     }
    219     if (umtx_initImplPreInit(uio)) {
    220         (*fp)();
    221         umtx_initImplPostInit(uio);
    222     }
    223 }
    224 
    225 // umtx_initOnce variant for plain functions, or static class functions.
    226 //               With ErrorCode, No context parameter.
    227 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
    228     if (U_FAILURE(errCode)) {
    229         return;
    230     }
    231     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
    232         // We run the initialization.
    233         (*fp)(errCode);
    234         uio.fErrCode = errCode;
    235         umtx_initImplPostInit(uio);
    236     } else {
    237         // Someone else already ran the initialization.
    238         if (U_FAILURE(uio.fErrCode)) {
    239             errCode = uio.fErrCode;
    240         }
    241     }
    242 }
    243 
    244 // umtx_initOnce variant for plain functions, or static class functions,
    245 //               with a context parameter.
    246 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
    247     if (umtx_loadAcquire(uio.fState) == 2) {
    248         return;
    249     }
    250     if (umtx_initImplPreInit(uio)) {
    251         (*fp)(context);
    252         umtx_initImplPostInit(uio);
    253     }
    254 }
    255 
    256 // umtx_initOnce variant for plain functions, or static class functions,
    257 //               with a context parameter and an error code.
    258 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
    259     if (U_FAILURE(errCode)) {
    260         return;
    261     }
    262     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
    263         // We run the initialization.
    264         (*fp)(context, errCode);
    265         uio.fErrCode = errCode;
    266         umtx_initImplPostInit(uio);
    267     } else {
    268         // Someone else already ran the initialization.
    269         if (U_FAILURE(uio.fErrCode)) {
    270             errCode = uio.fErrCode;
    271         }
    272     }
    273 }
    274 
    275 U_NAMESPACE_END
    276 
    277 
    278 
    279 /*************************************************************************************************
    280  *
    281  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
    282  *         TODO:  Add a C++11 version.
    283  *                Need to convert all mutex using files to C++ first.
    284  *
    285  *************************************************************************************************/
    286 
    287 #if defined(U_USER_MUTEX_H)
    288 // #inlcude "U_USER_MUTEX_H"
    289 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
    290 
    291 #elif U_PLATFORM_HAS_WIN32_API
    292 
    293 /* Windows Definitions.
    294  *    Windows comes first in the platform chain.
    295  *    Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
    296  */
    297 
    298 
    299 /* For CRITICAL_SECTION */
    300 
    301 /*
    302  *   Note: there is an earlier include of windows.h in this file, but it is in
    303  *         different conditionals.
    304  *         This one is needed if we are using C++11 for atomic ops, but
    305  *         win32 APIs for Critical Sections.
    306  */
    307 
    308 # define WIN32_LEAN_AND_MEAN
    309 # define VC_EXTRALEAN
    310 # define NOUSER
    311 # define NOSERVICE
    312 # define NOIME
    313 # define NOMCX
    314 # ifndef NOMINMAX
    315 # define NOMINMAX
    316 # endif
    317 # include <windows.h>
    318 
    319 
    320 typedef struct UMutex {
    321     icu::UInitOnce    fInitOnce;
    322     CRITICAL_SECTION  fCS;
    323 } UMutex;
    324 
    325 /* Initializer for a static UMUTEX. Deliberately contains no value for the
    326  *  CRITICAL_SECTION.
    327  */
    328 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
    329 
    330 
    331 
    332 #elif U_PLATFORM_IMPLEMENTS_POSIX
    333 
    334 /*
    335  *  POSIX platform
    336  */
    337 
    338 #include <pthread.h>
    339 
    340 struct UMutex {
    341     pthread_mutex_t  fMutex;
    342 };
    343 typedef struct UMutex UMutex;
    344 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
    345 
    346 #else
    347 
    348 /*
    349  *  Unknow platform type.
    350  *      This is an error condition. ICU requires mutexes.
    351  */
    352 
    353 #error Unknown Platform.
    354 
    355 #endif
    356 
    357 
    358 
    359 /**************************************************************************************
    360  *
    361  *  Mutex Implementation function declaratations.
    362  *     Declarations are platform neutral.
    363  *     Implementations, in umutex.cpp, are platform specific.
    364  *
    365  ************************************************************************************/
    366 
    367 /* Lock a mutex.
    368  * @param mutex The given mutex to be locked.  Pass NULL to specify
    369  *              the global ICU mutex.  Recursive locks are an error
    370  *              and may cause a deadlock on some platforms.
    371  */
    372 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
    373 
    374 /* Unlock a mutex.
    375  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
    376  *              the global ICU mutex.
    377  */
    378 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
    379 
    380 #endif /* UMUTEX_H */
    381 /*eof*/
    382