Home | History | Annotate | Download | only in common
      1 /*
      2 **********************************************************************
      3 *   Copyright (C) 1997-2012, 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 /* For _ReadWriteBarrier(). */
     26 #if defined(_MSC_VER) && _MSC_VER >= 1500
     27 # include <intrin.h>
     28 #endif
     29 
     30 /* For CRITICAL_SECTION */
     31 #if U_PLATFORM_HAS_WIN32_API
     32 #if 0
     33 /* TODO(andy): Why doesn't windows.h compile in all files? It does in some.
     34  *             The intent was to include windows.h here, and have struct UMutex
     35  *             have an embedded CRITICAL_SECTION when building on Windows.
     36  *             The workaround is to put some char[] storage in UMutex instead,
     37  *             avoiding the need to include windows.h everwhere this header is included.
     38  */
     39 # define WIN32_LEAN_AND_MEAN
     40 # define VC_EXTRALEAN
     41 # define NOUSER
     42 # define NOSERVICE
     43 # define NOIME
     44 # define NOMCX
     45 # include <windows.h>
     46 #endif  /* 0 */
     47 #define U_WINDOWS_CRIT_SEC_SIZE 64
     48 #endif  /* win32 */
     49 
     50 #if U_PLATFORM_IS_DARWIN_BASED
     51 #if defined(__STRICT_ANSI__)
     52 #define UPRV_REMAP_INLINE
     53 #define inline
     54 #endif
     55 #include <libkern/OSAtomic.h>
     56 #define USE_MAC_OS_ATOMIC_INCREMENT 1
     57 #if defined(UPRV_REMAP_INLINE)
     58 #undef inline
     59 #undef UPRV_REMAP_INLINE
     60 #endif
     61 #endif
     62 
     63 /*
     64  * If we do not compile with dynamic_annotations.h then define
     65  * empty annotation macros.
     66  *  See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
     67  */
     68 #ifndef ANNOTATE_HAPPENS_BEFORE
     69 # define ANNOTATE_HAPPENS_BEFORE(obj)
     70 # define ANNOTATE_HAPPENS_AFTER(obj)
     71 # define ANNOTATE_UNPROTECTED_READ(x) (x)
     72 #endif
     73 
     74 #ifndef UMTX_FULL_BARRIER
     75 # if U_HAVE_GCC_ATOMICS
     76 #  define UMTX_FULL_BARRIER __sync_synchronize();
     77 # elif defined(_MSC_VER) && _MSC_VER >= 1500
     78     /* From MSVC intrin.h. Use _ReadWriteBarrier() only on MSVC 9 and higher. */
     79 #  define UMTX_FULL_BARRIER _ReadWriteBarrier();
     80 # elif U_PLATFORM_IS_DARWIN_BASED
     81 #  define UMTX_FULL_BARRIER OSMemoryBarrier();
     82 # else
     83 #  define UMTX_FULL_BARRIER \
     84     { \
     85         umtx_lock(NULL); \
     86         umtx_unlock(NULL); \
     87     }
     88 # endif
     89 #endif
     90 
     91 #ifndef UMTX_ACQUIRE_BARRIER
     92 # define UMTX_ACQUIRE_BARRIER UMTX_FULL_BARRIER
     93 #endif
     94 
     95 #ifndef UMTX_RELEASE_BARRIER
     96 # define UMTX_RELEASE_BARRIER UMTX_FULL_BARRIER
     97 #endif
     98 
     99 /**
    100  * \def UMTX_CHECK
    101  * Encapsulates a safe check of an expression
    102  * for use with double-checked lazy inititialization.
    103  * Either memory barriers or mutexes are required, to prevent both the hardware
    104  * and the compiler from reordering operations across the check.
    105  * The expression must involve only a  _single_ variable, typically
    106  *    a possibly null pointer or a boolean that indicates whether some service
    107  *    is initialized or not.
    108  * The setting of the variable involved in the test must be the last step of
    109  *    the initialization process.
    110  *
    111  * @internal
    112  */
    113 #define UMTX_CHECK(pMutex, expression, result) \
    114     { \
    115         (result)=(expression); \
    116         UMTX_ACQUIRE_BARRIER; \
    117     }
    118 /*
    119  * TODO: Replace all uses of UMTX_CHECK and surrounding code
    120  * with SimpleSingleton or TriStateSingleton, and remove UMTX_CHECK.
    121  */
    122 
    123 /*
    124  * Code within ICU that accesses shared static or global data should
    125  * instantiate a Mutex object while doing so.  The unnamed global mutex
    126  * is used throughout ICU, so keep locking short and sweet.
    127  *
    128  * For example:
    129  *
    130  * void Function(int arg1, int arg2)
    131  * {
    132  *   static Object* foo;     // Shared read-write object
    133  *   umtx_lock(NULL);        // Lock the ICU global mutex
    134  *   foo->Method();
    135  *   umtx_unlock(NULL);
    136  * }
    137  *
    138  * an alternative C++ mutex API is defined in the file common/mutex.h
    139  */
    140 
    141 /*
    142  * UMutex - Mutexes for use by ICU implementation code.
    143  *          Must be declared as static or globals. They cannot appear as members
    144  *          of other objects.
    145  *          UMutex structs must be initialized.
    146  *          Example:
    147  *            static UMutex = U_MUTEX_INITIALIZER;
    148  *          The declaration of struct UMutex is platform dependent.
    149  */
    150 
    151 
    152 #if U_PLATFORM_HAS_WIN32_API
    153 
    154 /*  U_INIT_ONCE mimics the windows API INIT_ONCE, which exists on Windows Vista and newer.
    155  *  When ICU no longer needs to support older Windows platforms (XP) that do not have
    156  * a native INIT_ONCE, switch this implementation over to wrap the native Windows APIs.
    157  */
    158 typedef struct U_INIT_ONCE {
    159     long               fState;
    160     void              *fContext;
    161 } U_INIT_ONCE;
    162 #define U_INIT_ONCE_STATIC_INIT {0, NULL}
    163 
    164 typedef struct UMutex {
    165     U_INIT_ONCE       fInitOnce;
    166     UMTX              fUserMutex;
    167     UBool             fInitialized;  /* Applies to fUserMutex only. */
    168     /* CRITICAL_SECTION  fCS; */  /* See note above. Unresolved problems with including
    169                                    * Windows.h, which would allow using CRITICAL_SECTION
    170                                    * directly here. */
    171     char              fCS[U_WINDOWS_CRIT_SEC_SIZE];
    172 } UMutex;
    173 
    174 /* Initializer for a static UMUTEX. Deliberately contains no value for the
    175  *  CRITICAL_SECTION.
    176  */
    177 #define U_MUTEX_INITIALIZER {U_INIT_ONCE_STATIC_INIT, NULL, FALSE}
    178 
    179 #elif U_PLATFORM_IMPLEMENTS_POSIX
    180 #include <pthread.h>
    181 
    182 struct UMutex {
    183     pthread_mutex_t  fMutex;
    184     UMTX             fUserMutex;
    185     UBool            fInitialized;
    186 };
    187 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER, NULL, FALSE}
    188 
    189 #else
    190 /* Unknow platform type. */
    191 struct UMutex {
    192     void *fMutex;
    193 };
    194 #define U_MUTEX_INITIALIZER {NULL}
    195 #error Unknown Platform.
    196 
    197 #endif
    198 
    199 #if (U_PLATFORM != U_PF_CYGWIN && U_PLATFORM != U_PF_MINGW) || defined(CYGWINMSVC)
    200 typedef struct UMutex UMutex;
    201 #endif
    202 
    203 /* Lock a mutex.
    204  * @param mutex The given mutex to be locked.  Pass NULL to specify
    205  *              the global ICU mutex.  Recursive locks are an error
    206  *              and may cause a deadlock on some platforms.
    207  */
    208 U_CAPI void U_EXPORT2 umtx_lock(UMutex* mutex);
    209 
    210 /* Unlock a mutex.
    211  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
    212  *              the global ICU mutex.
    213  */
    214 U_CAPI void U_EXPORT2 umtx_unlock (UMutex* mutex);
    215 
    216 /*
    217  * Atomic Increment and Decrement of an int32_t value.
    218  *
    219  * Return Values:
    220  *   If the result of the operation is zero, the return zero.
    221  *   If the result of the operation is not zero, the sign of returned value
    222  *      is the same as the sign of the result, but the returned value itself may
    223  *      be different from the result of the operation.
    224  */
    225 U_CAPI int32_t U_EXPORT2 umtx_atomic_inc(int32_t *);
    226 U_CAPI int32_t U_EXPORT2 umtx_atomic_dec(int32_t *);
    227 
    228 #endif /*_CMUTEX*/
    229 /*eof*/
    230