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 
     97 U_NAMESPACE_BEGIN
     98 typedef volatile LONG u_atomic_int32_t;
     99 #define ATOMIC_INT32_T_INITIALIZER(val) val
    100 
    101 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    102     return InterlockedCompareExchange(&var, 0, 0);
    103 }
    104 
    105 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    106     InterlockedExchange(&var, val);
    107 }
    108 
    109 
    110 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
    111     return InterlockedIncrement(var);
    112 }
    113 
    114 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
    115     return InterlockedDecrement(var);
    116 }
    117 U_NAMESPACE_END
    118 
    119 
    120 #elif U_HAVE_GCC_ATOMICS
    121 /*
    122  * gcc atomic ops. These are available on several other compilers as well.
    123  */
    124 
    125 U_NAMESPACE_BEGIN
    126 typedef int32_t u_atomic_int32_t;
    127 #define ATOMIC_INT32_T_INITIALIZER(val) val
    128 
    129 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    130     int32_t val = var;
    131     __sync_synchronize();
    132     return val;
    133 }
    134 
    135 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    136     __sync_synchronize();
    137     var = val;
    138 }
    139 
    140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
    141    return __sync_add_and_fetch(p, 1);
    142 }
    143 
    144 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
    145    return __sync_sub_and_fetch(p, 1);
    146 }
    147 U_NAMESPACE_END
    148 
    149 #else
    150 
    151 /*
    152  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
    153  *                   Slow but correct.
    154  */
    155 
    156 #define U_NO_PLATFORM_ATOMICS
    157 
    158 U_NAMESPACE_BEGIN
    159 typedef int32_t u_atomic_int32_t;
    160 #define ATOMIC_INT32_T_INITIALIZER(val) val
    161 
    162 U_COMMON_API int32_t U_EXPORT2
    163 umtx_loadAcquire(u_atomic_int32_t &var);
    164 
    165 U_COMMON_API void U_EXPORT2
    166 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
    167 
    168 U_COMMON_API int32_t U_EXPORT2
    169 umtx_atomic_inc(u_atomic_int32_t *p);
    170 
    171 U_COMMON_API int32_t U_EXPORT2
    172 umtx_atomic_dec(u_atomic_int32_t *p);
    173 
    174 U_NAMESPACE_END
    175 
    176 #endif  /* Low Level Atomic Ops Platfrom Chain */
    177 
    178 
    179 
    180 /*************************************************************************************************
    181  *
    182  *  UInitOnce Definitions.
    183  *     These are platform neutral.
    184  *
    185  *************************************************************************************************/
    186 
    187 U_NAMESPACE_BEGIN
    188 
    189 struct UInitOnce {
    190     u_atomic_int32_t   fState;
    191     UErrorCode       fErrCode;
    192     void reset() {fState = 0;};
    193     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
    194 // Note: isReset() is used by service registration code.
    195 //                 Thread safety of this usage needs review.
    196 };
    197 
    198 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
    199 
    200 
    201 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
    202 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
    203 
    204 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
    205     if (umtx_loadAcquire(uio.fState) == 2) {
    206         return;
    207     }
    208     if (umtx_initImplPreInit(uio)) {
    209         (obj->*fp)();
    210         umtx_initImplPostInit(uio);
    211     }
    212 }
    213 
    214 
    215 // umtx_initOnce variant for plain functions, or static class functions.
    216 //               No context parameter.
    217 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
    218     if (umtx_loadAcquire(uio.fState) == 2) {
    219         return;
    220     }
    221     if (umtx_initImplPreInit(uio)) {
    222         (*fp)();
    223         umtx_initImplPostInit(uio);
    224     }
    225 }
    226 
    227 // umtx_initOnce variant for plain functions, or static class functions.
    228 //               With ErrorCode, No context parameter.
    229 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
    230     if (U_FAILURE(errCode)) {
    231         return;
    232     }
    233     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
    234         // We run the initialization.
    235         (*fp)(errCode);
    236         uio.fErrCode = errCode;
    237         umtx_initImplPostInit(uio);
    238     } else {
    239         // Someone else already ran the initialization.
    240         if (U_FAILURE(uio.fErrCode)) {
    241             errCode = uio.fErrCode;
    242         }
    243     }
    244 }
    245 
    246 // umtx_initOnce variant for plain functions, or static class functions,
    247 //               with a context parameter.
    248 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
    249     if (umtx_loadAcquire(uio.fState) == 2) {
    250         return;
    251     }
    252     if (umtx_initImplPreInit(uio)) {
    253         (*fp)(context);
    254         umtx_initImplPostInit(uio);
    255     }
    256 }
    257 
    258 // umtx_initOnce variant for plain functions, or static class functions,
    259 //               with a context parameter and an error code.
    260 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
    261     if (U_FAILURE(errCode)) {
    262         return;
    263     }
    264     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
    265         // We run the initialization.
    266         (*fp)(context, errCode);
    267         uio.fErrCode = errCode;
    268         umtx_initImplPostInit(uio);
    269     } else {
    270         // Someone else already ran the initialization.
    271         if (U_FAILURE(uio.fErrCode)) {
    272             errCode = uio.fErrCode;
    273         }
    274     }
    275 }
    276 
    277 U_NAMESPACE_END
    278 
    279 
    280 
    281 /*************************************************************************************************
    282  *
    283  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
    284  *         TODO:  Add a C++11 version.
    285  *                Need to convert all mutex using files to C++ first.
    286  *
    287  *************************************************************************************************/
    288 
    289 #if defined(U_USER_MUTEX_H)
    290 // #inlcude "U_USER_MUTEX_H"
    291 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
    292 
    293 #elif U_PLATFORM_HAS_WIN32_API
    294 
    295 /* Windows Definitions.
    296  *    Windows comes first in the platform chain.
    297  *    Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
    298  */
    299 
    300 
    301 /* For CRITICAL_SECTION */
    302 
    303 /*
    304  *   Note: there is an earlier include of windows.h in this file, but it is in
    305  *         different conditionals.
    306  *         This one is needed if we are using C++11 for atomic ops, but
    307  *         win32 APIs for Critical Sections.
    308  */
    309 
    310 # define WIN32_LEAN_AND_MEAN
    311 # define VC_EXTRALEAN
    312 # define NOUSER
    313 # define NOSERVICE
    314 # define NOIME
    315 # define NOMCX
    316 # ifndef NOMINMAX
    317 # define NOMINMAX
    318 # endif
    319 # include <windows.h>
    320 
    321 
    322 typedef struct UMutex {
    323     icu::UInitOnce         fInitOnce;
    324     CRITICAL_SECTION  fCS;
    325 } UMutex;
    326 
    327 /* Initializer for a static UMUTEX. Deliberately contains no value for the
    328  *  CRITICAL_SECTION.
    329  */
    330 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
    331 
    332 
    333 
    334 #elif U_PLATFORM_IMPLEMENTS_POSIX
    335 
    336 /*
    337  *  POSIX platform
    338  */
    339 
    340 #include <pthread.h>
    341 
    342 struct UMutex {
    343     pthread_mutex_t  fMutex;
    344 };
    345 typedef struct UMutex UMutex;
    346 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
    347 
    348 #else
    349 
    350 /*
    351  *  Unknow platform type.
    352  *      This is an error condition. ICU requires mutexes.
    353  */
    354 
    355 #error Unknown Platform.
    356 
    357 #endif
    358 
    359 
    360 
    361 /**************************************************************************************
    362  *
    363  *  Mutex Implementation function declaratations.
    364  *     Declarations are platform neutral.
    365  *     Implementations, in umutex.cpp, are platform specific.
    366  *
    367  ************************************************************************************/
    368 
    369 /* Lock a mutex.
    370  * @param mutex The given mutex to be locked.  Pass NULL to specify
    371  *              the global ICU mutex.  Recursive locks are an error
    372  *              and may cause a deadlock on some platforms.
    373  */
    374 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
    375 
    376 /* Unlock a mutex.
    377  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
    378  *              the global ICU mutex.
    379  */
    380 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
    381 
    382 #endif /* UMUTEX_H */
    383 /*eof*/
    384