• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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