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;
resetUInitOnce190 void reset() {fState = 0;};
isResetUInitOnce191 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
umtx_initOnce(UInitOnce & uio,T * obj,void (T::* fp)())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.
umtx_initOnce(UInitOnce & uio,void (* fp)())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.
umtx_initOnce(UInitOnce & uio,void (* fp)(UErrorCode &),UErrorCode & errCode)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.
umtx_initOnce(UInitOnce & uio,void (* fp)(T),T context)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.
umtx_initOnce(UInitOnce & uio,void (* fp)(T,UErrorCode &),T context,UErrorCode & errCode)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