]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/umutex.h
ICU-551.24.tar.gz
[apple/icu.git] / icuSources / common / umutex.h
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.
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_GCC_ATOMICS
122 /*
123 * gcc atomic ops. These are available on several other compilers as well.
124 */
125
126 U_NAMESPACE_BEGIN
127 typedef 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 int32_t val = var;
132 __sync_synchronize();
133 return val;
134 }
135
136 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
137 __sync_synchronize();
138 var = val;
139 }
140
141 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) {
142 return __sync_add_and_fetch(p, 1);
143 }
144
145 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) {
146 return __sync_sub_and_fetch(p, 1);
147 }
148 U_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
159 U_NAMESPACE_BEGIN
160 typedef int32_t u_atomic_int32_t;
161 #define ATOMIC_INT32_T_INITIALIZER(val) val
162
163 U_COMMON_API int32_t U_EXPORT2
164 umtx_loadAcquire(u_atomic_int32_t &var);
165
166 U_COMMON_API void U_EXPORT2
167 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
168
169 U_COMMON_API int32_t U_EXPORT2
170 umtx_atomic_inc(u_atomic_int32_t *p);
171
172 U_COMMON_API int32_t U_EXPORT2
173 umtx_atomic_dec(u_atomic_int32_t *p);
174
175 U_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
188 U_NAMESPACE_BEGIN
189
190 struct 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
202 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
203 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
204
205 template<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.
218 inline 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.
230 inline 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.
249 template<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.
261 template<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
278 U_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
323 typedef 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
333 struct 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
351 struct UMutex {
352 pthread_mutex_t fMutex;
353 };
354 typedef struct UMutex UMutex;
355 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER}
356
357 struct 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 */
388 U_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 */
394 U_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
405 U_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 */
415 U_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 */
421 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
422
423 #endif /* UMUTEX_H */
424 /*eof*/