]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.h
ICU-62107.0.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.h
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
b75a7d8f
A
3/*
4**********************************************************************
2ca993e8 5* Copyright (C) 1997-2015, International Business Machines
b75a7d8f
A
6* Corporation and others. All Rights Reserved.
7**********************************************************************
8*
9* File UMUTEX.H
10*
11* Modification History:
12*
13* Date Name Description
14* 04/02/97 aliu Creation.
15* 04/07/99 srl rewrite - C interface, multiple mutices
16* 05/13/99 stephen Changed to umutex (from cmutex)
17******************************************************************************
18*/
19
20#ifndef UMUTEX_H
21#define UMUTEX_H
22
23#include "unicode/utypes.h"
4388f060
A
24#include "unicode/uclean.h"
25#include "putilimp.h"
b75a7d8f 26
b75a7d8f 27
57a6839d
A
28
29// Forward Declarations. UMutex is not in the ICU namespace (yet) because
30// there are some remaining references from plain C.
31struct UMutex;
b331163b 32struct UConditionVar;
57a6839d
A
33
34U_NAMESPACE_BEGIN
35struct UInitOnce;
36U_NAMESPACE_END
37
38// Stringify macros, to allow #include of user supplied atomic & mutex files.
39#define U_MUTEX_STR(s) #s
40#define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
41
42/****************************************************************************
43 *
44 * Low Level Atomic Operations.
45 * Compiler dependent. Not operating system dependent.
46 *
47 ****************************************************************************/
48#if defined (U_USER_ATOMICS_H)
49#include U_MUTEX_XSTR(U_USER_ATOMICS_H)
50
51#elif U_HAVE_STD_ATOMICS
52
53// C++11 atomics are available.
54
55#include <atomic>
56
57U_NAMESPACE_BEGIN
58
59typedef std::atomic<int32_t> u_atomic_int32_t;
60#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
61
62inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
63 return var.load(std::memory_order_acquire);
64}
65
66inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
67 var.store(val, std::memory_order_release);
68}
69
70inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
71 return var->fetch_add(1) + 1;
72}
73
74inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
75 return var->fetch_sub(1) - 1;
76}
77U_NAMESPACE_END
78
79#elif U_PLATFORM_HAS_WIN32_API
80
81// MSVC compiler. Reads and writes of volatile variables have
82// acquire and release memory semantics, respectively.
83// This is a Microsoft extension, not standard C++ behavior.
84//
85// Update: can't use this because of MinGW, built with gcc.
86// Original plan was to use gcc atomics for MinGW, but they
87// aren't supported, so we fold MinGW into this path.
88
f3c0d7a5 89#ifndef WIN32_LEAN_AND_MEAN
51004dcb 90# define WIN32_LEAN_AND_MEAN
f3c0d7a5 91#endif
51004dcb
A
92# define VC_EXTRALEAN
93# define NOUSER
94# define NOSERVICE
95# define NOIME
96# define NOMCX
57a6839d
A
97# ifndef NOMINMAX
98# define NOMINMAX
99# endif
51004dcb 100# include <windows.h>
b75a7d8f 101
57a6839d
A
102U_NAMESPACE_BEGIN
103typedef volatile LONG u_atomic_int32_t;
104#define ATOMIC_INT32_T_INITIALIZER(val) val
105
106inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
107 return InterlockedCompareExchange(&var, 0, 0);
108}
109
110inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
111 InterlockedExchange(&var, val);
112}
113
114
115inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
116 return InterlockedIncrement(var);
117}
118
119inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
120 return InterlockedDecrement(var);
121}
122U_NAMESPACE_END
123
124
2ca993e8
A
125#elif U_HAVE_CLANG_ATOMICS
126/*
127 * Clang __c11 atomic built-ins
128 */
129
130U_NAMESPACE_BEGIN
131typedef _Atomic(int32_t) u_atomic_int32_t;
132#define ATOMIC_INT32_T_INITIALIZER(val) val
133
134inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
135 return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
136}
137
138inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
139 return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
140}
141
142inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
143 return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
144}
145
146inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
147 return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
148}
149U_NAMESPACE_END
150
151
57a6839d 152#elif U_HAVE_GCC_ATOMICS
4388f060 153/*
57a6839d 154 * gcc atomic ops. These are available on several other compilers as well.
73c04bcf 155 */
4388f060 156
57a6839d
A
157U_NAMESPACE_BEGIN
158typedef int32_t u_atomic_int32_t;
159#define ATOMIC_INT32_T_INITIALIZER(val) val
4388f060 160
57a6839d
A
161inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
162 int32_t val = var;
163 __sync_synchronize();
164 return val;
165}
4388f060 166
57a6839d
A
167inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
168 __sync_synchronize();
169 var = val;
170}
171
172inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) {
173 return __sync_add_and_fetch(p, 1);
174}
175
176inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) {
177 return __sync_sub_and_fetch(p, 1);
178}
179U_NAMESPACE_END
180
181#else
73c04bcf 182
4388f060 183/*
57a6839d
A
184 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
185 * Slow but correct.
4388f060 186 */
374ca955 187
57a6839d
A
188#define U_NO_PLATFORM_ATOMICS
189
190U_NAMESPACE_BEGIN
191typedef int32_t u_atomic_int32_t;
192#define ATOMIC_INT32_T_INITIALIZER(val) val
193
194U_COMMON_API int32_t U_EXPORT2
195umtx_loadAcquire(u_atomic_int32_t &var);
196
197U_COMMON_API void U_EXPORT2
198umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
199
200U_COMMON_API int32_t U_EXPORT2
201umtx_atomic_inc(u_atomic_int32_t *p);
202
203U_COMMON_API int32_t U_EXPORT2
204umtx_atomic_dec(u_atomic_int32_t *p);
205
206U_NAMESPACE_END
207
208#endif /* Low Level Atomic Ops Platfrom Chain */
209
210
211
212/*************************************************************************************************
b75a7d8f 213 *
57a6839d
A
214 * UInitOnce Definitions.
215 * These are platform neutral.
b75a7d8f 216 *
57a6839d
A
217 *************************************************************************************************/
218
219U_NAMESPACE_BEGIN
220
221struct UInitOnce {
222 u_atomic_int32_t fState;
223 UErrorCode fErrCode;
224 void reset() {fState = 0;};
225 UBool isReset() {return umtx_loadAcquire(fState) == 0;};
226// Note: isReset() is used by service registration code.
227// Thread safety of this usage needs review.
228};
229
230#define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
231
232
233U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
234U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
235
f3c0d7a5 236template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
57a6839d
A
237 if (umtx_loadAcquire(uio.fState) == 2) {
238 return;
239 }
240 if (umtx_initImplPreInit(uio)) {
241 (obj->*fp)();
242 umtx_initImplPostInit(uio);
243 }
244}
245
246
247// umtx_initOnce variant for plain functions, or static class functions.
248// No context parameter.
f3c0d7a5 249inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
57a6839d
A
250 if (umtx_loadAcquire(uio.fState) == 2) {
251 return;
252 }
253 if (umtx_initImplPreInit(uio)) {
254 (*fp)();
255 umtx_initImplPostInit(uio);
256 }
257}
258
259// umtx_initOnce variant for plain functions, or static class functions.
260// With ErrorCode, No context parameter.
f3c0d7a5 261inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
57a6839d
A
262 if (U_FAILURE(errCode)) {
263 return;
264 }
265 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
266 // We run the initialization.
267 (*fp)(errCode);
268 uio.fErrCode = errCode;
269 umtx_initImplPostInit(uio);
270 } else {
271 // Someone else already ran the initialization.
272 if (U_FAILURE(uio.fErrCode)) {
273 errCode = uio.fErrCode;
274 }
275 }
276}
277
278// umtx_initOnce variant for plain functions, or static class functions,
279// with a context parameter.
f3c0d7a5 280template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
57a6839d
A
281 if (umtx_loadAcquire(uio.fState) == 2) {
282 return;
283 }
284 if (umtx_initImplPreInit(uio)) {
285 (*fp)(context);
286 umtx_initImplPostInit(uio);
287 }
288}
289
290// umtx_initOnce variant for plain functions, or static class functions,
291// with a context parameter and an error code.
f3c0d7a5 292template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
57a6839d
A
293 if (U_FAILURE(errCode)) {
294 return;
295 }
296 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
297 // We run the initialization.
298 (*fp)(context, errCode);
299 uio.fErrCode = errCode;
300 umtx_initImplPostInit(uio);
301 } else {
302 // Someone else already ran the initialization.
303 if (U_FAILURE(uio.fErrCode)) {
304 errCode = uio.fErrCode;
305 }
306 }
307}
308
309U_NAMESPACE_END
310
311
312
313/*************************************************************************************************
b75a7d8f 314 *
57a6839d
A
315 * Mutex Definitions. Platform Dependent, #if platform chain follows.
316 * TODO: Add a C++11 version.
317 * Need to convert all mutex using files to C++ first.
318 *
319 *************************************************************************************************/
b75a7d8f 320
57a6839d
A
321#if defined(U_USER_MUTEX_H)
322// #inlcude "U_USER_MUTEX_H"
323#include U_MUTEX_XSTR(U_USER_MUTEX_H)
324
f3c0d7a5 325#elif U_PLATFORM_USES_ONLY_WIN32_API
51004dcb 326
57a6839d 327/* For CRITICAL_SECTION */
51004dcb 328
57a6839d
A
329/*
330 * Note: there is an earlier include of windows.h in this file, but it is in
331 * different conditionals.
332 * This one is needed if we are using C++11 for atomic ops, but
333 * win32 APIs for Critical Sections.
51004dcb 334 */
57a6839d 335
f3c0d7a5 336#ifndef WIN32_LEAN_AND_MEAN
57a6839d 337# define WIN32_LEAN_AND_MEAN
f3c0d7a5 338#endif
57a6839d
A
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
51004dcb
A
349
350typedef struct UMutex {
57a6839d
A
351 icu::UInitOnce fInitOnce;
352 CRITICAL_SECTION fCS;
51004dcb
A
353} UMutex;
354
355/* Initializer for a static UMUTEX. Deliberately contains no value for the
356 * CRITICAL_SECTION.
357 */
57a6839d
A
358#define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
359
b331163b
A
360struct UConditionVar {
361 HANDLE fEntryGate;
362 HANDLE fExitGate;
363 int32_t fWaitCount;
364};
365
366#define U_CONDITION_INITIALIZER {NULL, NULL, 0}
367
57a6839d 368
51004dcb
A
369
370#elif U_PLATFORM_IMPLEMENTS_POSIX
57a6839d
A
371
372/*
373 * POSIX platform
374 */
375
51004dcb
A
376#include <pthread.h>
377
378struct UMutex {
379 pthread_mutex_t fMutex;
51004dcb 380};
57a6839d
A
381typedef struct UMutex UMutex;
382#define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER}
51004dcb 383
b331163b
A
384struct UConditionVar {
385 pthread_cond_t fCondition;
386};
387#define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
388
51004dcb 389#else
57a6839d
A
390
391/*
392 * Unknow platform type.
393 * This is an error condition. ICU requires mutexes.
394 */
395
51004dcb
A
396#error Unknown Platform.
397
398#endif
399
57a6839d
A
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
4388f060 410/* Lock a mutex.
374ca955
A
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.
b75a7d8f 414 */
57a6839d 415U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
b75a7d8f 416
51004dcb 417/* Unlock a mutex.
374ca955
A
418 * @param mutex The given mutex to be unlocked. Pass NULL to specify
419 * the global ICU mutex.
b75a7d8f 420 */
57a6839d 421U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
b75a7d8f 422
b331163b
A
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
432U_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 */
442U_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 */
448U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
449
57a6839d 450#endif /* UMUTEX_H */
b75a7d8f 451/*eof*/