]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/umutex.h
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.h
1 /*
2 **********************************************************************
3 * Copyright (C) 1997-2015, 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 struct UConditionVar;
31
32 U_NAMESPACE_BEGIN
33 struct UInitOnce;
34 U_NAMESPACE_END
35
36 // Stringify macros, to allow #include of user supplied atomic & mutex files.
37 #define U_MUTEX_STR(s) #s
38 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
39
40 /****************************************************************************
41 *
42 * Low Level Atomic Operations.
43 * Compiler dependent. Not operating system dependent.
44 *
45 ****************************************************************************/
46 #if defined (U_USER_ATOMICS_H)
47 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
48
49 #elif U_HAVE_STD_ATOMICS
50
51 // C++11 atomics are available.
52
53 #include <atomic>
54
55 U_NAMESPACE_BEGIN
56
57 typedef std::atomic<int32_t> u_atomic_int32_t;
58 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
59
60 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
61 return var.load(std::memory_order_acquire);
62 }
63
64 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
65 var.store(val, std::memory_order_release);
66 }
67
68 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
69 return var->fetch_add(1) + 1;
70 }
71
72 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
73 return var->fetch_sub(1) - 1;
74 }
75 U_NAMESPACE_END
76
77 #elif U_PLATFORM_HAS_WIN32_API
78
79 // MSVC compiler. Reads and writes of volatile variables have
80 // acquire and release memory semantics, respectively.
81 // This is a Microsoft extension, not standard C++ behavior.
82 //
83 // Update: can't use this because of MinGW, built with gcc.
84 // Original plan was to use gcc atomics for MinGW, but they
85 // aren't supported, so we fold MinGW into this path.
86
87 # define WIN32_LEAN_AND_MEAN
88 # define VC_EXTRALEAN
89 # define NOUSER
90 # define NOSERVICE
91 # define NOIME
92 # define NOMCX
93 # ifndef NOMINMAX
94 # define NOMINMAX
95 # endif
96 # include <windows.h>
97
98 U_NAMESPACE_BEGIN
99 typedef volatile LONG u_atomic_int32_t;
100 #define ATOMIC_INT32_T_INITIALIZER(val) val
101
102 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
103 return InterlockedCompareExchange(&var, 0, 0);
104 }
105
106 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
107 InterlockedExchange(&var, val);
108 }
109
110
111 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
112 return InterlockedIncrement(var);
113 }
114
115 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
116 return InterlockedDecrement(var);
117 }
118 U_NAMESPACE_END
119
120
121 #elif U_HAVE_CLANG_ATOMICS
122 /*
123 * Clang __c11 atomic built-ins
124 */
125
126 U_NAMESPACE_BEGIN
127 typedef _Atomic(int32_t) u_atomic_int32_t;
128 #define ATOMIC_INT32_T_INITIALIZER(val) val
129
130 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
131 return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
132 }
133
134 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
135 return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
136 }
137
138 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
139 return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
140 }
141
142 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
143 return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
144 }
145 U_NAMESPACE_END
146
147
148 #elif U_HAVE_GCC_ATOMICS
149 /*
150 * gcc atomic ops. These are available on several other compilers as well.
151 */
152
153 U_NAMESPACE_BEGIN
154 typedef int32_t u_atomic_int32_t;
155 #define ATOMIC_INT32_T_INITIALIZER(val) val
156
157 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
158 int32_t val = var;
159 __sync_synchronize();
160 return val;
161 }
162
163 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
164 __sync_synchronize();
165 var = val;
166 }
167
168 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) {
169 return __sync_add_and_fetch(p, 1);
170 }
171
172 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) {
173 return __sync_sub_and_fetch(p, 1);
174 }
175 U_NAMESPACE_END
176
177 #else
178
179 /*
180 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
181 * Slow but correct.
182 */
183
184 #define U_NO_PLATFORM_ATOMICS
185
186 U_NAMESPACE_BEGIN
187 typedef int32_t u_atomic_int32_t;
188 #define ATOMIC_INT32_T_INITIALIZER(val) val
189
190 U_COMMON_API int32_t U_EXPORT2
191 umtx_loadAcquire(u_atomic_int32_t &var);
192
193 U_COMMON_API void U_EXPORT2
194 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
195
196 U_COMMON_API int32_t U_EXPORT2
197 umtx_atomic_inc(u_atomic_int32_t *p);
198
199 U_COMMON_API int32_t U_EXPORT2
200 umtx_atomic_dec(u_atomic_int32_t *p);
201
202 U_NAMESPACE_END
203
204 #endif /* Low Level Atomic Ops Platfrom Chain */
205
206
207
208 /*************************************************************************************************
209 *
210 * UInitOnce Definitions.
211 * These are platform neutral.
212 *
213 *************************************************************************************************/
214
215 U_NAMESPACE_BEGIN
216
217 struct UInitOnce {
218 u_atomic_int32_t fState;
219 UErrorCode fErrCode;
220 void reset() {fState = 0;};
221 UBool isReset() {return umtx_loadAcquire(fState) == 0;};
222 // Note: isReset() is used by service registration code.
223 // Thread safety of this usage needs review.
224 };
225
226 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
227
228
229 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
230 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
231
232 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
233 if (umtx_loadAcquire(uio.fState) == 2) {
234 return;
235 }
236 if (umtx_initImplPreInit(uio)) {
237 (obj->*fp)();
238 umtx_initImplPostInit(uio);
239 }
240 }
241
242
243 // umtx_initOnce variant for plain functions, or static class functions.
244 // No context parameter.
245 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
246 if (umtx_loadAcquire(uio.fState) == 2) {
247 return;
248 }
249 if (umtx_initImplPreInit(uio)) {
250 (*fp)();
251 umtx_initImplPostInit(uio);
252 }
253 }
254
255 // umtx_initOnce variant for plain functions, or static class functions.
256 // With ErrorCode, No context parameter.
257 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
258 if (U_FAILURE(errCode)) {
259 return;
260 }
261 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
262 // We run the initialization.
263 (*fp)(errCode);
264 uio.fErrCode = errCode;
265 umtx_initImplPostInit(uio);
266 } else {
267 // Someone else already ran the initialization.
268 if (U_FAILURE(uio.fErrCode)) {
269 errCode = uio.fErrCode;
270 }
271 }
272 }
273
274 // umtx_initOnce variant for plain functions, or static class functions,
275 // with a context parameter.
276 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
277 if (umtx_loadAcquire(uio.fState) == 2) {
278 return;
279 }
280 if (umtx_initImplPreInit(uio)) {
281 (*fp)(context);
282 umtx_initImplPostInit(uio);
283 }
284 }
285
286 // umtx_initOnce variant for plain functions, or static class functions,
287 // with a context parameter and an error code.
288 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
289 if (U_FAILURE(errCode)) {
290 return;
291 }
292 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
293 // We run the initialization.
294 (*fp)(context, errCode);
295 uio.fErrCode = errCode;
296 umtx_initImplPostInit(uio);
297 } else {
298 // Someone else already ran the initialization.
299 if (U_FAILURE(uio.fErrCode)) {
300 errCode = uio.fErrCode;
301 }
302 }
303 }
304
305 U_NAMESPACE_END
306
307
308
309 /*************************************************************************************************
310 *
311 * Mutex Definitions. Platform Dependent, #if platform chain follows.
312 * TODO: Add a C++11 version.
313 * Need to convert all mutex using files to C++ first.
314 *
315 *************************************************************************************************/
316
317 #if defined(U_USER_MUTEX_H)
318 // #inlcude "U_USER_MUTEX_H"
319 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
320
321 #elif U_PLATFORM_HAS_WIN32_API
322
323 /* Windows Definitions.
324 * Windows comes first in the platform chain.
325 * Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
326 */
327
328
329 /* For CRITICAL_SECTION */
330
331 /*
332 * Note: there is an earlier include of windows.h in this file, but it is in
333 * different conditionals.
334 * This one is needed if we are using C++11 for atomic ops, but
335 * win32 APIs for Critical Sections.
336 */
337
338 # define WIN32_LEAN_AND_MEAN
339 # define VC_EXTRALEAN
340 # define NOUSER
341 # define NOSERVICE
342 # define NOIME
343 # define NOMCX
344 # ifndef NOMINMAX
345 # define NOMINMAX
346 # endif
347 # include <windows.h>
348
349
350 typedef struct UMutex {
351 icu::UInitOnce fInitOnce;
352 CRITICAL_SECTION fCS;
353 } UMutex;
354
355 /* Initializer for a static UMUTEX. Deliberately contains no value for the
356 * CRITICAL_SECTION.
357 */
358 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
359
360 struct UConditionVar {
361 HANDLE fEntryGate;
362 HANDLE fExitGate;
363 int32_t fWaitCount;
364 };
365
366 #define U_CONDITION_INITIALIZER {NULL, NULL, 0}
367
368
369
370 #elif U_PLATFORM_IMPLEMENTS_POSIX
371
372 /*
373 * POSIX platform
374 */
375
376 #include <pthread.h>
377
378 struct UMutex {
379 pthread_mutex_t fMutex;
380 };
381 typedef struct UMutex UMutex;
382 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER}
383
384 struct UConditionVar {
385 pthread_cond_t fCondition;
386 };
387 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
388
389 #else
390
391 /*
392 * Unknow platform type.
393 * This is an error condition. ICU requires mutexes.
394 */
395
396 #error Unknown Platform.
397
398 #endif
399
400
401
402 /**************************************************************************************
403 *
404 * Mutex Implementation function declaratations.
405 * Declarations are platform neutral.
406 * Implementations, in umutex.cpp, are platform specific.
407 *
408 ************************************************************************************/
409
410 /* Lock a mutex.
411 * @param mutex The given mutex to be locked. Pass NULL to specify
412 * the global ICU mutex. Recursive locks are an error
413 * and may cause a deadlock on some platforms.
414 */
415 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
416
417 /* Unlock a mutex.
418 * @param mutex The given mutex to be unlocked. Pass NULL to specify
419 * the global ICU mutex.
420 */
421 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
422
423 /*
424 * Wait on a condition variable.
425 * The calling thread will unlock the mutex and wait on the condition variable.
426 * The mutex must be locked by the calling thread when invoking this function.
427 *
428 * @param cond the condition variable to wait on.
429 * @param mutex the associated mutex.
430 */
431
432 U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
433
434
435 /*
436 * Broadcast wakeup of all threads waiting on a Condition.
437 * The associated mutex must be locked by the calling thread when calling
438 * this function; this is a temporary ICU restriction.
439 *
440 * @param cond the condition variable.
441 */
442 U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
443
444 /*
445 * Signal a condition variable, waking up one waiting thread.
446 * CAUTION: Do not use. Place holder only. Not implemented for Windows.
447 */
448 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
449
450 #endif /* UMUTEX_H */
451 /*eof*/