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