2 **********************************************************************
3 * Copyright (C) 1997-2014, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
9 * Modification History:
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 ******************************************************************************
21 #include "unicode/utypes.h"
22 #include "unicode/uclean.h"
27 // Forward Declarations. UMutex is not in the ICU namespace (yet) because
28 // there are some remaining references from plain C.
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)
40 /****************************************************************************
42 * Low Level Atomic Operations.
43 * Compiler dependent. Not operating system dependent.
45 ****************************************************************************/
46 #if defined (U_USER_ATOMICS_H)
47 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
49 #elif U_HAVE_STD_ATOMICS
51 // C++11 atomics are available.
57 typedef std::atomic
<int32_t> u_atomic_int32_t
;
58 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
60 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
61 return var
.load(std::memory_order_acquire
);
64 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
65 var
.store(val
, std::memory_order_release
);
68 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*var
) {
69 return var
->fetch_add(1) + 1;
72 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*var
) {
73 return var
->fetch_sub(1) - 1;
77 #elif U_PLATFORM_HAS_WIN32_API
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.
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.
87 # define WIN32_LEAN_AND_MEAN
99 typedef volatile LONG u_atomic_int32_t
;
100 #define ATOMIC_INT32_T_INITIALIZER(val) val
102 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
103 return InterlockedCompareExchange(&var
, 0, 0);
106 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
107 InterlockedExchange(&var
, val
);
111 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*var
) {
112 return InterlockedIncrement(var
);
115 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*var
) {
116 return InterlockedDecrement(var
);
121 #elif U_HAVE_GCC_ATOMICS
123 * gcc atomic ops. These are available on several other compilers as well.
127 typedef int32_t u_atomic_int32_t
;
128 #define ATOMIC_INT32_T_INITIALIZER(val) val
130 inline int32_t umtx_loadAcquire(u_atomic_int32_t
&var
) {
132 __sync_synchronize();
136 inline void umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
137 __sync_synchronize();
141 inline int32_t umtx_atomic_inc(u_atomic_int32_t
*p
) {
142 return __sync_add_and_fetch(p
, 1);
145 inline int32_t umtx_atomic_dec(u_atomic_int32_t
*p
) {
146 return __sync_sub_and_fetch(p
, 1);
153 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
157 #define U_NO_PLATFORM_ATOMICS
160 typedef int32_t u_atomic_int32_t
;
161 #define ATOMIC_INT32_T_INITIALIZER(val) val
163 U_COMMON_API
int32_t U_EXPORT2
164 umtx_loadAcquire(u_atomic_int32_t
&var
);
166 U_COMMON_API
void U_EXPORT2
167 umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
);
169 U_COMMON_API
int32_t U_EXPORT2
170 umtx_atomic_inc(u_atomic_int32_t
*p
);
172 U_COMMON_API
int32_t U_EXPORT2
173 umtx_atomic_dec(u_atomic_int32_t
*p
);
177 #endif /* Low Level Atomic Ops Platfrom Chain */
181 /*************************************************************************************************
183 * UInitOnce Definitions.
184 * These are platform neutral.
186 *************************************************************************************************/
191 u_atomic_int32_t fState
;
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.
199 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
202 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce
&);
203 U_COMMON_API
void U_EXPORT2
umtx_initImplPostInit(UInitOnce
&);
205 template<class T
> void umtx_initOnce(UInitOnce
&uio
, T
*obj
, void (T::*fp
)()) {
206 if (umtx_loadAcquire(uio
.fState
) == 2) {
209 if (umtx_initImplPreInit(uio
)) {
211 umtx_initImplPostInit(uio
);
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) {
222 if (umtx_initImplPreInit(uio
)) {
224 umtx_initImplPostInit(uio
);
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
)) {
234 if (umtx_loadAcquire(uio
.fState
) != 2 && umtx_initImplPreInit(uio
)) {
235 // We run the initialization.
237 uio
.fErrCode
= errCode
;
238 umtx_initImplPostInit(uio
);
240 // Someone else already ran the initialization.
241 if (U_FAILURE(uio
.fErrCode
)) {
242 errCode
= uio
.fErrCode
;
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) {
253 if (umtx_initImplPreInit(uio
)) {
255 umtx_initImplPostInit(uio
);
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
)) {
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
);
271 // Someone else already ran the initialization.
272 if (U_FAILURE(uio
.fErrCode
)) {
273 errCode
= uio
.fErrCode
;
282 /*************************************************************************************************
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.
288 *************************************************************************************************/
290 #if defined(U_USER_MUTEX_H)
291 // #inlcude "U_USER_MUTEX_H"
292 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
294 #elif U_PLATFORM_HAS_WIN32_API
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.
302 /* For CRITICAL_SECTION */
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.
311 # define WIN32_LEAN_AND_MEAN
312 # define VC_EXTRALEAN
320 # include <windows.h>
323 typedef struct UMutex
{
324 icu::UInitOnce fInitOnce
;
325 CRITICAL_SECTION fCS
;
328 /* Initializer for a static UMUTEX. Deliberately contains no value for the
331 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
333 struct UConditionVar
{
339 #define U_CONDITION_INITIALIZER {NULL, NULL, 0}
343 #elif U_PLATFORM_IMPLEMENTS_POSIX
352 pthread_mutex_t fMutex
;
354 typedef struct UMutex UMutex
;
355 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER}
357 struct UConditionVar
{
358 pthread_cond_t fCondition
;
360 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
365 * Unknow platform type.
366 * This is an error condition. ICU requires mutexes.
369 #error Unknown Platform.
375 /**************************************************************************************
377 * Mutex Implementation function declaratations.
378 * Declarations are platform neutral.
379 * Implementations, in umutex.cpp, are platform specific.
381 ************************************************************************************/
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.
388 U_INTERNAL
void U_EXPORT2
umtx_lock(UMutex
* mutex
);
391 * @param mutex The given mutex to be unlocked. Pass NULL to specify
392 * the global ICU mutex.
394 U_INTERNAL
void U_EXPORT2
umtx_unlock (UMutex
* mutex
);
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.
401 * @param cond the condition variable to wait on.
402 * @param mutex the associated mutex.
405 U_INTERNAL
void U_EXPORT2
umtx_condWait(UConditionVar
*cond
, UMutex
*mutex
);
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.
413 * @param cond the condition variable.
415 U_INTERNAL
void U_EXPORT2
umtx_condBroadcast(UConditionVar
*cond
);
418 * Signal a condition variable, waking up one waiting thread.
419 * CAUTION: Do not use. Place holder only. Not implemented for Windows.
421 U_INTERNAL
void U_EXPORT2
umtx_condSignal(UConditionVar
*cond
);
423 #endif /* UMUTEX_H */