intl/icu/source/common/umutex.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     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 */
    18 #ifndef UMUTEX_H
    19 #define UMUTEX_H
    21 #include "unicode/utypes.h"
    22 #include "unicode/uclean.h"
    23 #include "putilimp.h"
    27 // Forward Declarations. UMutex is not in the ICU namespace (yet) because
    28 //                       there are some remaining references from plain C.
    29 struct UMutex;
    31 U_NAMESPACE_BEGIN
    32 struct UInitOnce;
    33 U_NAMESPACE_END
    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)
    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)
    48 #elif U_HAVE_STD_ATOMICS
    50 //  C++11 atomics are available.
    52 #include <atomic>
    54 U_NAMESPACE_BEGIN
    56 typedef std::atomic<int32_t> u_atomic_int32_t;
    57 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
    59 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
    60     return var.load(std::memory_order_acquire);
    61 }
    63 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
    64     var.store(val, std::memory_order_release);
    65 }
    67 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
    68     return var->fetch_add(1) + 1;
    69 }
    71 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
    72     return var->fetch_sub(1) - 1;
    73 }
    74 U_NAMESPACE_END
    76 #elif U_PLATFORM_HAS_WIN32_API
    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.
    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>
    97 U_NAMESPACE_BEGIN
    98 typedef volatile LONG u_atomic_int32_t;
    99 #define ATOMIC_INT32_T_INITIALIZER(val) val
   101 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
   102     return InterlockedCompareExchange(&var, 0, 0);
   103 }
   105 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
   106     InterlockedExchange(&var, val);
   107 }
   110 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
   111     return InterlockedIncrement(var);
   112 }
   114 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
   115     return InterlockedDecrement(var);
   116 }
   117 U_NAMESPACE_END
   120 #elif U_HAVE_GCC_ATOMICS
   121 /*
   122  * gcc atomic ops. These are available on several other compilers as well.
   123  */
   125 U_NAMESPACE_BEGIN
   126 typedef int32_t u_atomic_int32_t;
   127 #define ATOMIC_INT32_T_INITIALIZER(val) val
   129 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
   130     int32_t val = var;
   131     __sync_synchronize();
   132     return val;
   133 }
   135 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
   136     __sync_synchronize();
   137     var = val;
   138 }
   140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
   141    return __sync_add_and_fetch(p, 1);
   142 }
   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
   149 #else
   151 /*
   152  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
   153  *                   Slow but correct.
   154  */
   156 #define U_NO_PLATFORM_ATOMICS
   158 U_NAMESPACE_BEGIN
   159 typedef int32_t u_atomic_int32_t;
   160 #define ATOMIC_INT32_T_INITIALIZER(val) val
   162 U_COMMON_API int32_t U_EXPORT2 
   163 umtx_loadAcquire(u_atomic_int32_t &var);
   165 U_COMMON_API void U_EXPORT2 
   166 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
   168 U_COMMON_API int32_t U_EXPORT2 
   169 umtx_atomic_inc(u_atomic_int32_t *p);
   171 U_COMMON_API int32_t U_EXPORT2 
   172 umtx_atomic_dec(u_atomic_int32_t *p);
   174 U_NAMESPACE_END
   176 #endif  /* Low Level Atomic Ops Platfrom Chain */
   180 /*************************************************************************************************
   181  *
   182  *  UInitOnce Definitions.
   183  *     These are platform neutral.
   184  *
   185  *************************************************************************************************/
   187 U_NAMESPACE_BEGIN
   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 };
   198 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
   201 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
   202 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
   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 }
   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 }
   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 }
   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 }
   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 }
   277 U_NAMESPACE_END
   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  *************************************************************************************************/
   289 #if defined(U_USER_MUTEX_H)
   290 // #inlcude "U_USER_MUTEX_H"
   291 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
   293 #elif U_PLATFORM_HAS_WIN32_API
   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  */
   301 /* For CRITICAL_SECTION */
   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  */
   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>
   322 typedef struct UMutex {
   323     icu::UInitOnce    fInitOnce;
   324     CRITICAL_SECTION  fCS;
   325 } UMutex;
   327 /* Initializer for a static UMUTEX. Deliberately contains no value for the
   328  *  CRITICAL_SECTION.
   329  */
   330 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
   334 #elif U_PLATFORM_IMPLEMENTS_POSIX
   336 /*
   337  *  POSIX platform
   338  */
   340 #include <pthread.h>
   342 struct UMutex {
   343     pthread_mutex_t  fMutex;
   344 };
   345 typedef struct UMutex UMutex;
   346 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
   348 #else
   350 /*
   351  *  Unknow platform type.
   352  *      This is an error condition. ICU requires mutexes.
   353  */
   355 #error Unknown Platform.
   357 #endif
   361 /**************************************************************************************
   362  *
   363  *  Mutex Implementation function declaratations.
   364  *     Declarations are platform neutral.
   365  *     Implementations, in umutex.cpp, are platform specific.
   366  *
   367  ************************************************************************************/
   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);
   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);
   382 #endif /* UMUTEX_H */
   383 /*eof*/

mercurial