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