1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
13 * Modification History:
15 * Date Name Description
16 * 04/02/97 aliu Creation.
17 * 04/07/99 srl updated
18 * 05/13/99 stephen Changed to umutex (from cmutex).
19 * 11/22/99 aliu Make non-global mutex autoinitialize [j151]
20 ******************************************************************************
25 #include "unicode/utypes.h"
30 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
31 static UMutex globalMutex
= U_MUTEX_INITIALIZER
;
34 * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a
35 * platform independent set of mutex operations. For internal ICU use only.
38 #if defined(U_USER_MUTEX_CPP)
39 // Build time user mutex hook: #include "U_USER_MUTEX_CPP"
40 #include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
42 #elif U_PLATFORM_USES_ONLY_WIN32_API
44 #if defined U_NO_PLATFORM_ATOMICS
45 #error ICU on Win32 requires support for low level atomic operations.
46 // Visual Studio, gcc, clang are OK. Shouldn't get here.
50 // This function is called when a test of a UInitOnce::fState reveals that
51 // initialization has not completed, that we either need to call the
52 // function on this thread, or wait for some other thread to complete.
54 // The actual call to the init function is made inline by template code
55 // that knows the C++ types involved. This function returns TRUE if
56 // the caller needs to call the Init function.
61 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce
&uio
) {
63 int32_t previousState
= InterlockedCompareExchange(
64 (LONG
volatile *) // this is the type given in the API doc for this function.
65 &uio
.fState
, // Destination
69 if (previousState
== 0) {
70 return true; // Caller will next call the init function.
71 // Current state == 1.
72 } else if (previousState
== 2) {
73 // Another thread already completed the initialization.
74 // We can simply return FALSE, indicating no
75 // further action is needed by the caller.
78 // Another thread is currently running the initialization.
79 // Wait until it completes.
82 previousState
= umtx_loadAcquire(uio
.fState
);
83 } while (previousState
== 1);
88 // This function is called by the thread that ran an initialization function,
89 // just after completing the function.
91 U_COMMON_API
void U_EXPORT2
umtx_initImplPostInit(UInitOnce
&uio
) {
92 umtx_storeRelease(uio
.fState
, 2);
97 static void winMutexInit(CRITICAL_SECTION
*cs
) {
98 InitializeCriticalSection(cs
);
102 U_CAPI
void U_EXPORT2
103 umtx_lock(UMutex
*mutex
) {
105 mutex
= &globalMutex
;
107 CRITICAL_SECTION
*cs
= &mutex
->fCS
;
108 umtx_initOnce(mutex
->fInitOnce
, winMutexInit
, cs
);
109 EnterCriticalSection(cs
);
112 U_CAPI
void U_EXPORT2
113 umtx_unlock(UMutex
* mutex
)
116 mutex
= &globalMutex
;
118 LeaveCriticalSection(&mutex
->fCS
);
122 U_CAPI
void U_EXPORT2
123 umtx_condBroadcast(UConditionVar
*condition
) {
124 // We require that the associated mutex be held by the caller,
125 // so access to fWaitCount is protected and safe. No other thread can
126 // call condWait() while we are here.
127 if (condition
->fWaitCount
== 0) {
130 ResetEvent(condition
->fExitGate
);
131 SetEvent(condition
->fEntryGate
);
134 U_CAPI
void U_EXPORT2
135 umtx_condSignal(UConditionVar
* /* condition */) {
136 // Function not implemented. There is no immediate requirement from ICU to have it.
137 // Once ICU drops support for Windows XP and Server 2003, ICU Condition Variables will be
138 // changed to be thin wrappers on native Windows CONDITION_VARIABLEs, and this function
139 // becomes trivial to provide.
143 U_CAPI
void U_EXPORT2
144 umtx_condWait(UConditionVar
*condition
, UMutex
*mutex
) {
145 if (condition
->fEntryGate
== NULL
) {
146 // Note: because the associated mutex must be locked when calling
147 // wait, we know that there can not be multiple threads
148 // running here with the same condition variable.
149 // Meaning that lazy initialization is safe.
150 U_ASSERT(condition
->fExitGate
== NULL
);
151 condition
->fEntryGate
= CreateEvent(NULL
, // Security Attributes
152 TRUE
, // Manual Reset
153 FALSE
, // Initially reset
155 U_ASSERT(condition
->fEntryGate
!= NULL
);
156 condition
->fExitGate
= CreateEvent(NULL
, TRUE
, TRUE
, NULL
);
157 U_ASSERT(condition
->fExitGate
!= NULL
);
160 condition
->fWaitCount
++;
162 WaitForSingleObject(condition
->fEntryGate
, INFINITE
);
164 condition
->fWaitCount
--;
165 if (condition
->fWaitCount
== 0) {
166 // All threads that were waiting at the entry gate have woken up
167 // and moved through. Shut the entry gate and open the exit gate.
168 ResetEvent(condition
->fEntryGate
);
169 SetEvent(condition
->fExitGate
);
172 WaitForSingleObject(condition
->fExitGate
, INFINITE
);
178 #elif U_PLATFORM_IMPLEMENTS_POSIX
180 //-------------------------------------------------------------------------------------------
182 // POSIX specific definitions
184 //-------------------------------------------------------------------------------------------
186 # include <pthread.h>
188 // Each UMutex consists of a pthread_mutex_t.
189 // All are statically initialized and ready for use.
190 // There is no runtime mutex initialization code needed.
192 U_CAPI
void U_EXPORT2
193 umtx_lock(UMutex
*mutex
) {
195 mutex
= &globalMutex
;
197 int sysErr
= pthread_mutex_lock(&mutex
->fMutex
);
198 (void)sysErr
; // Suppress unused variable warnings.
199 U_ASSERT(sysErr
== 0);
203 U_CAPI
void U_EXPORT2
204 umtx_unlock(UMutex
* mutex
)
207 mutex
= &globalMutex
;
209 int sysErr
= pthread_mutex_unlock(&mutex
->fMutex
);
210 (void)sysErr
; // Suppress unused variable warnings.
211 U_ASSERT(sysErr
== 0);
215 U_CAPI
void U_EXPORT2
216 umtx_condWait(UConditionVar
*cond
, UMutex
*mutex
) {
218 mutex
= &globalMutex
;
220 int sysErr
= pthread_cond_wait(&cond
->fCondition
, &mutex
->fMutex
);
222 U_ASSERT(sysErr
== 0);
225 U_CAPI
void U_EXPORT2
226 umtx_condBroadcast(UConditionVar
*cond
) {
227 int sysErr
= pthread_cond_broadcast(&cond
->fCondition
);
229 U_ASSERT(sysErr
== 0);
232 U_CAPI
void U_EXPORT2
233 umtx_condSignal(UConditionVar
*cond
) {
234 int sysErr
= pthread_cond_signal(&cond
->fCondition
);
236 U_ASSERT(sysErr
== 0);
243 static pthread_mutex_t initMutex
= PTHREAD_MUTEX_INITIALIZER
;
244 static pthread_cond_t initCondition
= PTHREAD_COND_INITIALIZER
;
247 // This function is called when a test of a UInitOnce::fState reveals that
248 // initialization has not completed, that we either need to call the
249 // function on this thread, or wait for some other thread to complete.
251 // The actual call to the init function is made inline by template code
252 // that knows the C++ types involved. This function returns TRUE if
253 // the caller needs to call the Init function.
255 U_COMMON_API UBool U_EXPORT2
256 umtx_initImplPreInit(UInitOnce
&uio
) {
257 pthread_mutex_lock(&initMutex
);
258 int32_t state
= uio
.fState
;
260 umtx_storeRelease(uio
.fState
, 1);
261 pthread_mutex_unlock(&initMutex
);
262 return TRUE
; // Caller will next call the init function.
264 while (uio
.fState
== 1) {
265 // Another thread is currently running the initialization.
266 // Wait until it completes.
267 pthread_cond_wait(&initCondition
, &initMutex
);
269 pthread_mutex_unlock(&initMutex
);
270 U_ASSERT(uio
.fState
== 2);
277 // This function is called by the thread that ran an initialization function,
278 // just after completing the function.
279 // Some threads may be waiting on the condition, requiring the broadcast wakeup.
280 // Some threads may be racing to test the fState variable outside of the mutex,
281 // requiring the use of store/release when changing its value.
283 U_COMMON_API
void U_EXPORT2
284 umtx_initImplPostInit(UInitOnce
&uio
) {
285 pthread_mutex_lock(&initMutex
);
286 umtx_storeRelease(uio
.fState
, 2);
287 pthread_cond_broadcast(&initCondition
);
288 pthread_mutex_unlock(&initMutex
);
293 // End of POSIX specific umutex implementation.
295 #else // Platform #define chain.
297 #error Unknown Platform
299 #endif // Platform #define chain.
302 //-------------------------------------------------------------------------------
304 // Atomic Operations, out-of-line versions.
305 // These are conditional, only defined if better versions
306 // were not available for the platform.
308 // These versions are platform neutral.
310 //--------------------------------------------------------------------------------
312 #if defined U_NO_PLATFORM_ATOMICS
313 static UMutex gIncDecMutex
= U_MUTEX_INITIALIZER
;
317 U_COMMON_API
int32_t U_EXPORT2
318 umtx_atomic_inc(u_atomic_int32_t
*p
) {
320 umtx_lock(&gIncDecMutex
);
322 umtx_unlock(&gIncDecMutex
);
327 U_COMMON_API
int32_t U_EXPORT2
328 umtx_atomic_dec(u_atomic_int32_t
*p
) {
330 umtx_lock(&gIncDecMutex
);
332 umtx_unlock(&gIncDecMutex
);
336 U_COMMON_API
int32_t U_EXPORT2
337 umtx_loadAcquire(u_atomic_int32_t
&var
) {
338 umtx_lock(&gIncDecMutex
);
340 umtx_unlock(&gIncDecMutex
);
344 U_COMMON_API
void U_EXPORT2
345 umtx_storeRelease(u_atomic_int32_t
&var
, int32_t val
) {
346 umtx_lock(&gIncDecMutex
);
348 umtx_unlock(&gIncDecMutex
);
354 //--------------------------------------------------------------------------
356 // Deprecated functions for setting user mutexes.
358 //--------------------------------------------------------------------------
360 U_DEPRECATED
void U_EXPORT2
361 u_setMutexFunctions(const void * /*context */, UMtxInitFn
*, UMtxFn
*,
362 UMtxFn
*, UMtxFn
*, UErrorCode
*status
) {
363 if (U_SUCCESS(*status
)) {
364 *status
= U_UNSUPPORTED_ERROR
;
371 U_DEPRECATED
void U_EXPORT2
372 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn
*, UMtxAtomicFn
*,
373 UErrorCode
*status
) {
374 if (U_SUCCESS(*status
)) {
375 *status
= U_UNSUPPORTED_ERROR
;