2 **********************************************************************
3 * Copyright (C) 1997-2013, 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.
35 // Stringify macros, to allow #include of user supplied atomic & mutex files.
36 #define U_MUTEX_STR(s) #s
37 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
39 /****************************************************************************
41 * Low Level Atomic Operations.
42 * Compiler dependent. Not operating system dependent.
44 ****************************************************************************/
45 #if defined (U_USER_ATOMICS_H)
46 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
48 #elif U_HAVE_STD_ATOMICS
50 // C++11 atomics are available.
56 typedef std::atomic<int32_t> u_atomic_int32_t;
57 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
59 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
60 return var.load(std::memory_order_acquire);
63 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
64 var.store(val, std::memory_order_release);
67 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
68 return var->fetch_add(1) + 1;
71 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
72 return var->fetch_sub(1) - 1;
76 #elif U_PLATFORM_HAS_WIN32_API
78 // MSVC compiler. Reads and writes of volatile variables have
79 // acquire and release memory semantics, respectively.
80 // This is a Microsoft extension, not standard C++ behavior.
82 // Update: can't use this because of MinGW, built with gcc.
83 // Original plan was to use gcc atomics for MinGW, but they
84 // aren't supported, so we fold MinGW into this path.
86 # define WIN32_LEAN_AND_MEAN
98 typedef volatile LONG u_atomic_int32_t;
99 #define ATOMIC_INT32_T_INITIALIZER(val) val
101 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
102 return InterlockedCompareExchange(&var, 0, 0);
105 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
106 InterlockedExchange(&var, val);
110 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
111 return InterlockedIncrement(var);
114 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
115 return InterlockedDecrement(var);
120 #elif U_HAVE_GCC_ATOMICS
122 * gcc atomic ops. These are available on several other compilers as well.
126 typedef int32_t u_atomic_int32_t;
127 #define ATOMIC_INT32_T_INITIALIZER(val) val
129 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
131 __sync_synchronize();
135 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
136 __sync_synchronize();
140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) {
141 return __sync_add_and_fetch(p, 1);
144 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) {
145 return __sync_sub_and_fetch(p, 1);
152 * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
156 #define U_NO_PLATFORM_ATOMICS
159 typedef int32_t u_atomic_int32_t;
160 #define ATOMIC_INT32_T_INITIALIZER(val) val
162 U_COMMON_API int32_t U_EXPORT2
163 umtx_loadAcquire(u_atomic_int32_t &var);
165 U_COMMON_API void U_EXPORT2
166 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
168 U_COMMON_API int32_t U_EXPORT2
169 umtx_atomic_inc(u_atomic_int32_t *p);
171 U_COMMON_API int32_t U_EXPORT2
172 umtx_atomic_dec(u_atomic_int32_t *p);
176 #endif /* Low Level Atomic Ops Platfrom Chain */
180 /*************************************************************************************************
182 * UInitOnce Definitions.
183 * These are platform neutral.
185 *************************************************************************************************/
190 u_atomic_int32_t fState;
192 void reset() {fState = 0;};
193 UBool isReset() {return umtx_loadAcquire(fState) == 0;};
194 // Note: isReset() is used by service registration code.
195 // Thread safety of this usage needs review.
198 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
201 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
202 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
204 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
205 if (umtx_loadAcquire(uio.fState) == 2) {
208 if (umtx_initImplPreInit(uio)) {
210 umtx_initImplPostInit(uio);
215 // umtx_initOnce variant for plain functions, or static class functions.
216 // No context parameter.
217 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
218 if (umtx_loadAcquire(uio.fState) == 2) {
221 if (umtx_initImplPreInit(uio)) {
223 umtx_initImplPostInit(uio);
227 // umtx_initOnce variant for plain functions, or static class functions.
228 // With ErrorCode, No context parameter.
229 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
230 if (U_FAILURE(errCode)) {
233 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
234 // We run the initialization.
236 uio.fErrCode = errCode;
237 umtx_initImplPostInit(uio);
239 // Someone else already ran the initialization.
240 if (U_FAILURE(uio.fErrCode)) {
241 errCode = uio.fErrCode;
246 // umtx_initOnce variant for plain functions, or static class functions,
247 // with a context parameter.
248 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
249 if (umtx_loadAcquire(uio.fState) == 2) {
252 if (umtx_initImplPreInit(uio)) {
254 umtx_initImplPostInit(uio);
258 // umtx_initOnce variant for plain functions, or static class functions,
259 // with a context parameter and an error code.
260 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
261 if (U_FAILURE(errCode)) {
264 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
265 // We run the initialization.
266 (*fp)(context, errCode);
267 uio.fErrCode = errCode;
268 umtx_initImplPostInit(uio);
270 // Someone else already ran the initialization.
271 if (U_FAILURE(uio.fErrCode)) {
272 errCode = uio.fErrCode;
281 /*************************************************************************************************
283 * Mutex Definitions. Platform Dependent, #if platform chain follows.
284 * TODO: Add a C++11 version.
285 * Need to convert all mutex using files to C++ first.
287 *************************************************************************************************/
289 #if defined(U_USER_MUTEX_H)
290 // #inlcude "U_USER_MUTEX_H"
291 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
293 #elif U_PLATFORM_HAS_WIN32_API
295 /* Windows Definitions.
296 * Windows comes first in the platform chain.
297 * Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
301 /* For CRITICAL_SECTION */
304 * Note: there is an earlier include of windows.h in this file, but it is in
305 * different conditionals.
306 * This one is needed if we are using C++11 for atomic ops, but
307 * win32 APIs for Critical Sections.
310 # define WIN32_LEAN_AND_MEAN
311 # define VC_EXTRALEAN
319 # include <windows.h>
322 typedef struct UMutex {
323 icu::UInitOnce fInitOnce;
324 CRITICAL_SECTION fCS;
327 /* Initializer for a static UMUTEX. Deliberately contains no value for the
330 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
334 #elif U_PLATFORM_IMPLEMENTS_POSIX
343 pthread_mutex_t fMutex;
345 typedef struct UMutex UMutex;
346 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER}
351 * Unknow platform type.
352 * This is an error condition. ICU requires mutexes.
355 #error Unknown Platform.
361 /**************************************************************************************
363 * Mutex Implementation function declaratations.
364 * Declarations are platform neutral.
365 * Implementations, in umutex.cpp, are platform specific.
367 ************************************************************************************/
370 * @param mutex The given mutex to be locked. Pass NULL to specify
371 * the global ICU mutex. Recursive locks are an error
372 * and may cause a deadlock on some platforms.
374 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
377 * @param mutex The given mutex to be unlocked. Pass NULL to specify
378 * the global ICU mutex.
380 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
382 #endif /* UMUTEX_H */