2 ******************************************************************************
4 * Copyright (C) 1997-2013, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
11 * Modification History:
13 * Date Name Description
14 * 04/02/97 aliu Creation.
15 * 04/07/99 srl updated
16 * 05/13/99 stephen Changed to umutex (from cmutex).
17 * 11/22/99 aliu Make non-global mutex autoinitialize [j151]
18 ******************************************************************************
23 #include "unicode/utypes.h"
29 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
30 static UMutex globalMutex
= U_MUTEX_INITIALIZER
;
33 * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a
34 * platform independent set of mutex operations. For internal ICU use only.
37 #if defined(U_USER_MUTEX_CPP)
38 // Build time user mutex hook: #include "U_USER_MUTEX_CPP"
39 #include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
41 #elif U_PLATFORM_HAS_WIN32_API
43 //-------------------------------------------------------------------------------------------
45 // Windows Specific Definitions
47 // Note: Cygwin (and possibly others) have both WIN32 and POSIX.
48 // Prefer Win32 in these cases. (Win32 comes ahead in the #if chain)
50 //-------------------------------------------------------------------------------------------
52 #if defined U_NO_PLATFORM_ATOMICS
53 #error ICU on Win32 requires support for low level atomic operations.
54 // Visual Studio, gcc, clang are OK. Shouldn't get here.
58 // This function is called when a test of a UInitOnce::fState reveals that
59 // initialization has not completed, that we either need to call the
60 // function on this thread, or wait for some other thread to complete.
62 // The actual call to the init function is made inline by template code
63 // that knows the C++ types involved. This function returns TRUE if
64 // the caller needs to call the Init function.
69 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce
&uio
) {
71 int32_t previousState
= InterlockedCompareExchange(
72 #if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN)
73 (LONG
volatile *) // this is the type given in the API doc for this function.
75 &uio
.fState
, // Destination
79 if (previousState
== 0) {
80 return true; // Caller will next call the init function.
81 // Current state == 1.
82 } else if (previousState
== 2) {
83 // Another thread already completed the initialization.
84 // We can simply return FALSE, indicating no
85 // further action is needed by the caller.
88 // Another thread is currently running the initialization.
89 // Wait until it completes.
92 previousState
= umtx_loadAcquire(uio
.fState
);
93 } while (previousState
== 1);
98 // This function is called by the thread that ran an initialization function,
99 // just after completing the function.
101 // success: True: the inialization succeeded. No further calls to the init
102 // function will be made.
103 // False: the initializtion failed. The next call to umtx_initOnce()
104 // will retry the initialization.
106 U_COMMON_API
void U_EXPORT2
umtx_initImplPostInit(UInitOnce
&uio
) {
107 umtx_storeRelease(uio
.fState
, 2);
112 static void winMutexInit(CRITICAL_SECTION
*cs
) {
113 InitializeCriticalSection(cs
);
117 U_CAPI
void U_EXPORT2
118 umtx_lock(UMutex
*mutex
) {
120 mutex
= &globalMutex
;
122 CRITICAL_SECTION
*cs
= &mutex
->fCS
;
123 umtx_initOnce(mutex
->fInitOnce
, winMutexInit
, cs
);
124 EnterCriticalSection(cs
);
127 U_CAPI
void U_EXPORT2
128 umtx_unlock(UMutex
* mutex
)
131 mutex
= &globalMutex
;
133 LeaveCriticalSection(&mutex
->fCS
);
136 #elif U_PLATFORM_IMPLEMENTS_POSIX
138 //-------------------------------------------------------------------------------------------
140 // POSIX specific definitions
142 //-------------------------------------------------------------------------------------------
144 # include <pthread.h>
146 // Each UMutex consists of a pthread_mutex_t.
147 // All are statically initialized and ready for use.
148 // There is no runtime mutex initialization code needed.
150 U_CAPI
void U_EXPORT2
151 umtx_lock(UMutex
*mutex
) {
153 mutex
= &globalMutex
;
155 int sysErr
= pthread_mutex_lock(&mutex
->fMutex
);
156 (void)sysErr
; // Suppress unused variable warnings.
157 U_ASSERT(sysErr
== 0);
161 U_CAPI
void U_EXPORT2
162 umtx_unlock(UMutex
* mutex
)
165 mutex
= &globalMutex
;
167 int sysErr
= pthread_mutex_unlock(&mutex
->fMutex
);
168 (void)sysErr
; // Suppress unused variable warnings.
169 U_ASSERT(sysErr
== 0);
174 static pthread_mutex_t initMutex
= PTHREAD_MUTEX_INITIALIZER
;
175 static pthread_cond_t initCondition
= PTHREAD_COND_INITIALIZER
;
178 // This function is called when a test of a UInitOnce::fState reveals that
179 // initialization has not completed, that we either need to call the
180 // function on this thread, or wait for some other thread to complete.
182 // The actual call to the init function is made inline by template code
183 // that knows the C++ types involved. This function returns TRUE if
184 // the caller needs to call the Init function.
186 U_COMMON_API UBool U_EXPORT2
187 umtx_initImplPreInit(UInitOnce
&uio
) {
188 pthread_mutex_lock(&initMutex
);
189 int32_t state
= uio
.fState
;
191 umtx_storeRelease(uio
.fState
, 1);
192 pthread_mutex_unlock(&initMutex
);
193 return TRUE
; // Caller will next call the init function.
195 while (uio
.fState
== 1) {
196 // Another thread is currently running the initialization.
197 // Wait until it completes.
198 pthread_cond_wait(&initCondition
, &initMutex
);
200 pthread_mutex_unlock(&initMutex
);
201 U_ASSERT(uio
.fState
== 2);
208 // This function is called by the thread that ran an initialization function,
209 // just after completing the function.
210 // Some threads may be waiting on the condition, requiring the broadcast wakeup.
211 // Some threads may be racing to test the fState variable outside of the mutex,
212 // requiring the use of store/release when changing its value.
214 U_COMMON_API
void U_EXPORT2
215 umtx_initImplPostInit(UInitOnce
&uio
) {
216 pthread_mutex_lock(&initMutex
);
217 umtx_storeRelease(uio
.fState
, 2);
218 pthread_cond_broadcast(&initCondition
);
219 pthread_mutex_unlock(&initMutex
);
224 // End of POSIX specific umutex implementation.
226 #else // Platform #define chain.
228 #error Unknown Platform
230 #endif // Platform #define chain.
233 //-------------------------------------------------------------------------------
235 // Atomic Operations, out-of-line versions.
236 // These are conditional, only defined if better versions
237 // were not available for the platform.
239 // These versions are platform neutral.
241 //--------------------------------------------------------------------------------
243 #if defined U_NO_PLATFORM_ATOMICS
244 static UMutex gIncDecMutex
= U_MUTEX_INITIALIZER
;
248 U_COMMON_API
int32_t U_EXPORT2
249 umtx_atomic_inc(u_atomic_int32_t
*p
) {
251 umtx_lock(&gIncDecMutex
);
253 umtx_unlock(&gIncDecMutex
);
258 U_COMMON_API
int32_t U_EXPORT2
259 umtx_atomic_dec(u_atomic_int32_t
*p
) {
261 umtx_lock(&gIncDecMutex
);
263 umtx_unlock(&gIncDecMutex
);
267 U_COMMON_API
int32_t U_EXPORT2
268 umtx_loadAcquire(u_atomic_int32_t
&var
) {
270 umtx_lock(&gIncDecMutex
);
271 umtx_unlock(&gIncDecMutex
);
275 U_COMMON_API
void U_EXPORT2
276 umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
277 umtx_lock(&gIncDecMutex
);
278 umtx_unlock(&gIncDecMutex
);
285 //--------------------------------------------------------------------------
287 // Deprecated functions for setting user mutexes.
289 //--------------------------------------------------------------------------
291 U_DEPRECATED
void U_EXPORT2
292 u_setMutexFunctions(const void * /*context */, UMtxInitFn
*, UMtxFn
*,
293 UMtxFn
*, UMtxFn
*, UErrorCode
*status
) {
294 if (U_SUCCESS(*status
)) {
295 *status
= U_UNSUPPORTED_ERROR
;
302 U_DEPRECATED
void U_EXPORT2
303 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn
*, UMtxAtomicFn
*,
304 UErrorCode
*status
) {
305 if (U_SUCCESS(*status
)) {
306 *status
= U_UNSUPPORTED_ERROR
;