2 ******************************************************************************
4 * Copyright (C) 1997-2015, 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"
28 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
29 static UMutex globalMutex
= U_MUTEX_INITIALIZER
;
32 * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a
33 * platform independent set of mutex operations. For internal ICU use only.
36 #if defined(U_USER_MUTEX_CPP)
37 // Build time user mutex hook: #include "U_USER_MUTEX_CPP"
38 #include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
40 #elif U_PLATFORM_HAS_WIN32_API
42 //-------------------------------------------------------------------------------------------
44 // Windows Specific Definitions
46 // Note: Cygwin (and possibly others) have both WIN32 and POSIX.
47 // Prefer Win32 in these cases. (Win32 comes ahead in the #if chain)
49 //-------------------------------------------------------------------------------------------
51 #if defined U_NO_PLATFORM_ATOMICS
52 #error ICU on Win32 requires support for low level atomic operations.
53 // Visual Studio, gcc, clang are OK. Shouldn't get here.
57 // This function is called when a test of a UInitOnce::fState reveals that
58 // initialization has not completed, that we either need to call the
59 // function on this thread, or wait for some other thread to complete.
61 // The actual call to the init function is made inline by template code
62 // that knows the C++ types involved. This function returns TRUE if
63 // the caller needs to call the Init function.
68 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce
&uio
) {
70 int32_t previousState
= InterlockedCompareExchange(
71 #if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN) || defined(__clang__)
72 (LONG
volatile *) // this is the type given in the API doc for this function.
74 &uio
.fState
, // Destination
78 if (previousState
== 0) {
79 return true; // Caller will next call the init function.
80 // Current state == 1.
81 } else if (previousState
== 2) {
82 // Another thread already completed the initialization.
83 // We can simply return FALSE, indicating no
84 // further action is needed by the caller.
87 // Another thread is currently running the initialization.
88 // Wait until it completes.
91 previousState
= umtx_loadAcquire(uio
.fState
);
92 } while (previousState
== 1);
97 // This function is called by the thread that ran an initialization function,
98 // just after completing the function.
100 U_COMMON_API
void U_EXPORT2
umtx_initImplPostInit(UInitOnce
&uio
) {
101 umtx_storeRelease(uio
.fState
, 2);
106 static void winMutexInit(CRITICAL_SECTION
*cs
) {
107 InitializeCriticalSection(cs
);
111 U_CAPI
void U_EXPORT2
112 umtx_lock(UMutex
*mutex
) {
114 mutex
= &globalMutex
;
116 CRITICAL_SECTION
*cs
= &mutex
->fCS
;
117 umtx_initOnce(mutex
->fInitOnce
, winMutexInit
, cs
);
118 EnterCriticalSection(cs
);
121 U_CAPI
void U_EXPORT2
122 umtx_unlock(UMutex
* mutex
)
125 mutex
= &globalMutex
;
127 LeaveCriticalSection(&mutex
->fCS
);
131 U_CAPI
void U_EXPORT2
132 umtx_condBroadcast(UConditionVar
*condition
) {
133 // We require that the associated mutex be held by the caller,
134 // so access to fWaitCount is protected and safe. No other thread can
135 // call condWait() while we are here.
136 if (condition
->fWaitCount
== 0) {
139 ResetEvent(condition
->fExitGate
);
140 SetEvent(condition
->fEntryGate
);
143 U_CAPI
void U_EXPORT2
144 umtx_condSignal(UConditionVar
*condition
) {
145 // Function not implemented. There is no immediate requirement from ICU to have it.
146 // Once ICU drops support for Windows XP and Server 2003, ICU Condition Variables will be
147 // changed to be thin wrappers on native Windows CONDITION_VARIABLEs, and this function
148 // becomes trivial to provide.
152 U_CAPI
void U_EXPORT2
153 umtx_condWait(UConditionVar
*condition
, UMutex
*mutex
) {
154 if (condition
->fEntryGate
== NULL
) {
155 // Note: because the associated mutex must be locked when calling
156 // wait, we know that there can not be multiple threads
157 // running here with the same condition variable.
158 // Meaning that lazy initialization is safe.
159 U_ASSERT(condition
->fExitGate
== NULL
);
160 condition
->fEntryGate
= CreateEvent(NULL
, // Security Attributes
161 TRUE
, // Manual Reset
162 FALSE
, // Initially reset
164 U_ASSERT(condition
->fEntryGate
!= NULL
);
165 condition
->fExitGate
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
166 U_ASSERT(condition
->fExitGate
!= NULL
);
169 condition
->fWaitCount
++;
171 WaitForSingleObject(condition
->fEntryGate
, INFINITE
);
173 condition
->fWaitCount
--;
174 if (condition
->fWaitCount
== 0) {
175 // All threads that were waiting at the entry gate have woken up
176 // and moved through. Shut the entry gate and open the exit gate.
177 ResetEvent(condition
->fEntryGate
);
178 SetEvent(condition
->fExitGate
);
181 WaitForSingleObject(condition
->fExitGate
, INFINITE
);
187 #elif U_PLATFORM_IMPLEMENTS_POSIX
189 //-------------------------------------------------------------------------------------------
191 // POSIX specific definitions
193 //-------------------------------------------------------------------------------------------
195 # include <pthread.h>
197 // Each UMutex consists of a pthread_mutex_t.
198 // All are statically initialized and ready for use.
199 // There is no runtime mutex initialization code needed.
201 U_CAPI
void U_EXPORT2
202 umtx_lock(UMutex
*mutex
) {
204 mutex
= &globalMutex
;
206 int sysErr
= pthread_mutex_lock(&mutex
->fMutex
);
207 (void)sysErr
; // Suppress unused variable warnings.
208 U_ASSERT(sysErr
== 0);
212 U_CAPI
void U_EXPORT2
213 umtx_unlock(UMutex
* mutex
)
216 mutex
= &globalMutex
;
218 int sysErr
= pthread_mutex_unlock(&mutex
->fMutex
);
219 (void)sysErr
; // Suppress unused variable warnings.
220 U_ASSERT(sysErr
== 0);
224 U_CAPI
void U_EXPORT2
225 umtx_condWait(UConditionVar
*cond
, UMutex
*mutex
) {
227 mutex
= &globalMutex
;
229 int sysErr
= pthread_cond_wait(&cond
->fCondition
, &mutex
->fMutex
);
231 U_ASSERT(sysErr
== 0);
234 U_CAPI
void U_EXPORT2
235 umtx_condBroadcast(UConditionVar
*cond
) {
236 int sysErr
= pthread_cond_broadcast(&cond
->fCondition
);
238 U_ASSERT(sysErr
== 0);
241 U_CAPI
void U_EXPORT2
242 umtx_condSignal(UConditionVar
*cond
) {
243 int sysErr
= pthread_cond_signal(&cond
->fCondition
);
245 U_ASSERT(sysErr
== 0);
252 static pthread_mutex_t initMutex
= PTHREAD_MUTEX_INITIALIZER
;
253 static pthread_cond_t initCondition
= PTHREAD_COND_INITIALIZER
;
256 // This function is called when a test of a UInitOnce::fState reveals that
257 // initialization has not completed, that we either need to call the
258 // function on this thread, or wait for some other thread to complete.
260 // The actual call to the init function is made inline by template code
261 // that knows the C++ types involved. This function returns TRUE if
262 // the caller needs to call the Init function.
264 U_COMMON_API UBool U_EXPORT2
265 umtx_initImplPreInit(UInitOnce
&uio
) {
266 pthread_mutex_lock(&initMutex
);
267 int32_t state
= uio
.fState
;
269 umtx_storeRelease(uio
.fState
, 1);
270 pthread_mutex_unlock(&initMutex
);
271 return TRUE
; // Caller will next call the init function.
273 while (uio
.fState
== 1) {
274 // Another thread is currently running the initialization.
275 // Wait until it completes.
276 pthread_cond_wait(&initCondition
, &initMutex
);
278 pthread_mutex_unlock(&initMutex
);
279 U_ASSERT(uio
.fState
== 2);
286 // This function is called by the thread that ran an initialization function,
287 // just after completing the function.
288 // Some threads may be waiting on the condition, requiring the broadcast wakeup.
289 // Some threads may be racing to test the fState variable outside of the mutex,
290 // requiring the use of store/release when changing its value.
292 U_COMMON_API
void U_EXPORT2
293 umtx_initImplPostInit(UInitOnce
&uio
) {
294 pthread_mutex_lock(&initMutex
);
295 umtx_storeRelease(uio
.fState
, 2);
296 pthread_cond_broadcast(&initCondition
);
297 pthread_mutex_unlock(&initMutex
);
302 // End of POSIX specific umutex implementation.
304 #else // Platform #define chain.
306 #error Unknown Platform
308 #endif // Platform #define chain.
311 //-------------------------------------------------------------------------------
313 // Atomic Operations, out-of-line versions.
314 // These are conditional, only defined if better versions
315 // were not available for the platform.
317 // These versions are platform neutral.
319 //--------------------------------------------------------------------------------
321 #if defined U_NO_PLATFORM_ATOMICS
322 static UMutex gIncDecMutex
= U_MUTEX_INITIALIZER
;
326 U_COMMON_API
int32_t U_EXPORT2
327 umtx_atomic_inc(u_atomic_int32_t
*p
) {
329 umtx_lock(&gIncDecMutex
);
331 umtx_unlock(&gIncDecMutex
);
336 U_COMMON_API
int32_t U_EXPORT2
337 umtx_atomic_dec(u_atomic_int32_t
*p
) {
339 umtx_lock(&gIncDecMutex
);
341 umtx_unlock(&gIncDecMutex
);
345 U_COMMON_API
int32_t U_EXPORT2
346 umtx_loadAcquire(u_atomic_int32_t
&var
) {
347 umtx_lock(&gIncDecMutex
);
349 umtx_unlock(&gIncDecMutex
);
353 U_COMMON_API
void U_EXPORT2
354 umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
355 umtx_lock(&gIncDecMutex
);
357 umtx_unlock(&gIncDecMutex
);
363 //--------------------------------------------------------------------------
365 // Deprecated functions for setting user mutexes.
367 //--------------------------------------------------------------------------
369 U_DEPRECATED
void U_EXPORT2
370 u_setMutexFunctions(const void * /*context */, UMtxInitFn
*, UMtxFn
*,
371 UMtxFn
*, UMtxFn
*, UErrorCode
*status
) {
372 if (U_SUCCESS(*status
)) {
373 *status
= U_UNSUPPORTED_ERROR
;
380 U_DEPRECATED
void U_EXPORT2
381 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn
*, UMtxAtomicFn
*,
382 UErrorCode
*status
) {
383 if (U_SUCCESS(*status
)) {
384 *status
= U_UNSUPPORTED_ERROR
;