]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.cpp
ICU-57166.0.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.cpp
CommitLineData
51004dcb
A
1/*
2******************************************************************************
3*
b331163b 4* Copyright (C) 1997-2015, International Business Machines
51004dcb
A
5* Corporation and others. All Rights Reserved.
6*
7******************************************************************************
8*
9* File umutex.cpp
10*
11* Modification History:
12*
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******************************************************************************
19*/
20
57a6839d
A
21#include "umutex.h"
22
51004dcb
A
23#include "unicode/utypes.h"
24#include "uassert.h"
57a6839d 25#include "cmemory.h"
51004dcb 26
57a6839d
A
27
28// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
29static UMutex globalMutex = U_MUTEX_INITIALIZER;
30
51004dcb
A
31/*
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.
34 */
35
57a6839d
A
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)
51004dcb 39
57a6839d 40#elif U_PLATFORM_HAS_WIN32_API
51004dcb 41
57a6839d
A
42//-------------------------------------------------------------------------------------------
43//
44// Windows Specific Definitions
45//
46// Note: Cygwin (and possibly others) have both WIN32 and POSIX.
47// Prefer Win32 in these cases. (Win32 comes ahead in the #if chain)
48//
49//-------------------------------------------------------------------------------------------
51004dcb 50
57a6839d
A
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.
51004dcb
A
54#endif
55
51004dcb 56
57a6839d
A
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.
51004dcb 60//
57a6839d
A
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.
51004dcb 64//
51004dcb 65
57a6839d 66U_NAMESPACE_BEGIN
51004dcb 67
57a6839d
A
68U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
69 for (;;) {
70 int32_t previousState = InterlockedCompareExchange(
b331163b 71#if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN) || defined(__clang__)
57a6839d
A
72 (LONG volatile *) // this is the type given in the API doc for this function.
73#endif
74 &uio.fState, // Destination
75 1, // Exchange Value
76 0); // Compare value
77
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.
85 return FALSE;
86 } else {
87 // Another thread is currently running the initialization.
88 // Wait until it completes.
89 do {
90 Sleep(1);
91 previousState = umtx_loadAcquire(uio.fState);
92 } while (previousState == 1);
51004dcb 93 }
51004dcb 94 }
51004dcb
A
95}
96
57a6839d
A
97// This function is called by the thread that ran an initialization function,
98// just after completing the function.
51004dcb 99
57a6839d
A
100U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
101 umtx_storeRelease(uio.fState, 2);
51004dcb 102}
51004dcb 103
57a6839d 104U_NAMESPACE_END
51004dcb 105
57a6839d
A
106static void winMutexInit(CRITICAL_SECTION *cs) {
107 InitializeCriticalSection(cs);
108 return;
109}
51004dcb
A
110
111U_CAPI void U_EXPORT2
112umtx_lock(UMutex *mutex) {
113 if (mutex == NULL) {
114 mutex = &globalMutex;
115 }
57a6839d
A
116 CRITICAL_SECTION *cs = &mutex->fCS;
117 umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
118 EnterCriticalSection(cs);
51004dcb
A
119}
120
51004dcb
A
121U_CAPI void U_EXPORT2
122umtx_unlock(UMutex* mutex)
123{
124 if (mutex == NULL) {
125 mutex = &globalMutex;
126 }
57a6839d 127 LeaveCriticalSection(&mutex->fCS);
51004dcb
A
128}
129
b331163b
A
130
131U_CAPI void U_EXPORT2
132umtx_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) {
137 return;
138 }
139 ResetEvent(condition->fExitGate);
140 SetEvent(condition->fEntryGate);
141}
142
143U_CAPI void U_EXPORT2
144umtx_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.
149 U_ASSERT(FALSE);
150}
151
152U_CAPI void U_EXPORT2
153umtx_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
163 NULL); // Name.
164 U_ASSERT(condition->fEntryGate != NULL);
165 condition->fExitGate = CreateEvent(NULL, TRUE, TRUE, NULL);
166 U_ASSERT(condition->fExitGate != NULL);
167 }
168
169 condition->fWaitCount++;
170 umtx_unlock(mutex);
171 WaitForSingleObject(condition->fEntryGate, INFINITE);
172 umtx_lock(mutex);
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);
179 } else {
180 umtx_unlock(mutex);
181 WaitForSingleObject(condition->fExitGate, INFINITE);
182 umtx_lock(mutex);
183 }
184}
185
186
57a6839d
A
187#elif U_PLATFORM_IMPLEMENTS_POSIX
188
189//-------------------------------------------------------------------------------------------
51004dcb 190//
57a6839d 191// POSIX specific definitions
51004dcb 192//
57a6839d
A
193//-------------------------------------------------------------------------------------------
194
195# include <pthread.h>
196
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.
51004dcb 200
51004dcb
A
201U_CAPI void U_EXPORT2
202umtx_lock(UMutex *mutex) {
203 if (mutex == NULL) {
204 mutex = &globalMutex;
205 }
57a6839d
A
206 int sysErr = pthread_mutex_lock(&mutex->fMutex);
207 (void)sysErr; // Suppress unused variable warnings.
208 U_ASSERT(sysErr == 0);
51004dcb
A
209}
210
57a6839d 211
51004dcb
A
212U_CAPI void U_EXPORT2
213umtx_unlock(UMutex* mutex)
214{
215 if (mutex == NULL) {
216 mutex = &globalMutex;
217 }
57a6839d
A
218 int sysErr = pthread_mutex_unlock(&mutex->fMutex);
219 (void)sysErr; // Suppress unused variable warnings.
220 U_ASSERT(sysErr == 0);
51004dcb
A
221}
222
b331163b
A
223
224U_CAPI void U_EXPORT2
225umtx_condWait(UConditionVar *cond, UMutex *mutex) {
226 if (mutex == NULL) {
227 mutex = &globalMutex;
228 }
229 int sysErr = pthread_cond_wait(&cond->fCondition, &mutex->fMutex);
230 (void)sysErr;
231 U_ASSERT(sysErr == 0);
232}
233
234U_CAPI void U_EXPORT2
235umtx_condBroadcast(UConditionVar *cond) {
236 int sysErr = pthread_cond_broadcast(&cond->fCondition);
237 (void)sysErr;
238 U_ASSERT(sysErr == 0);
239}
240
241U_CAPI void U_EXPORT2
242umtx_condSignal(UConditionVar *cond) {
243 int sysErr = pthread_cond_signal(&cond->fCondition);
244 (void)sysErr;
245 U_ASSERT(sysErr == 0);
246}
247
248
249
57a6839d 250U_NAMESPACE_BEGIN
51004dcb 251
57a6839d
A
252static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
253static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
51004dcb 254
51004dcb 255
57a6839d
A
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.
259//
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.
263//
264U_COMMON_API UBool U_EXPORT2
265umtx_initImplPreInit(UInitOnce &uio) {
266 pthread_mutex_lock(&initMutex);
267 int32_t state = uio.fState;
268 if (state == 0) {
269 umtx_storeRelease(uio.fState, 1);
270 pthread_mutex_unlock(&initMutex);
271 return TRUE; // Caller will next call the init function.
272 } else {
273 while (uio.fState == 1) {
274 // Another thread is currently running the initialization.
275 // Wait until it completes.
276 pthread_cond_wait(&initCondition, &initMutex);
277 }
278 pthread_mutex_unlock(&initMutex);
279 U_ASSERT(uio.fState == 2);
280 return FALSE;
51004dcb 281 }
57a6839d 282}
51004dcb 283
51004dcb 284
57a6839d
A
285
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.
291
292U_COMMON_API void U_EXPORT2
293umtx_initImplPostInit(UInitOnce &uio) {
294 pthread_mutex_lock(&initMutex);
295 umtx_storeRelease(uio.fState, 2);
296 pthread_cond_broadcast(&initCondition);
297 pthread_mutex_unlock(&initMutex);
51004dcb
A
298}
299
57a6839d 300U_NAMESPACE_END
51004dcb 301
57a6839d 302// End of POSIX specific umutex implementation.
51004dcb 303
57a6839d 304#else // Platform #define chain.
51004dcb 305
57a6839d 306#error Unknown Platform
51004dcb 307
57a6839d 308#endif // Platform #define chain.
51004dcb 309
51004dcb 310
57a6839d
A
311//-------------------------------------------------------------------------------
312//
313// Atomic Operations, out-of-line versions.
314// These are conditional, only defined if better versions
315// were not available for the platform.
316//
317// These versions are platform neutral.
318//
319//--------------------------------------------------------------------------------
51004dcb 320
57a6839d 321#if defined U_NO_PLATFORM_ATOMICS
51004dcb 322static UMutex gIncDecMutex = U_MUTEX_INITIALIZER;
51004dcb 323
57a6839d
A
324U_NAMESPACE_BEGIN
325
326U_COMMON_API int32_t U_EXPORT2
327umtx_atomic_inc(u_atomic_int32_t *p) {
51004dcb 328 int32_t retVal;
57a6839d
A
329 umtx_lock(&gIncDecMutex);
330 retVal = ++(*p);
331 umtx_unlock(&gIncDecMutex);
51004dcb
A
332 return retVal;
333}
334
57a6839d
A
335
336U_COMMON_API int32_t U_EXPORT2
337umtx_atomic_dec(u_atomic_int32_t *p) {
51004dcb 338 int32_t retVal;
57a6839d
A
339 umtx_lock(&gIncDecMutex);
340 retVal = --(*p);
341 umtx_unlock(&gIncDecMutex);
51004dcb
A
342 return retVal;
343}
344
57a6839d
A
345U_COMMON_API int32_t U_EXPORT2
346umtx_loadAcquire(u_atomic_int32_t &var) {
57a6839d 347 umtx_lock(&gIncDecMutex);
2ca993e8 348 int32_t val = var;
57a6839d
A
349 umtx_unlock(&gIncDecMutex);
350 return val;
351}
352
353U_COMMON_API void U_EXPORT2
354umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
355 umtx_lock(&gIncDecMutex);
57a6839d 356 var = val;
2ca993e8 357 umtx_unlock(&gIncDecMutex);
57a6839d 358}
51004dcb 359
57a6839d
A
360U_NAMESPACE_END
361#endif
51004dcb 362
57a6839d
A
363//--------------------------------------------------------------------------
364//
365// Deprecated functions for setting user mutexes.
366//
367//--------------------------------------------------------------------------
51004dcb 368
57a6839d
A
369U_DEPRECATED void U_EXPORT2
370u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
371 UMtxFn *, UMtxFn *, UErrorCode *status) {
372 if (U_SUCCESS(*status)) {
373 *status = U_UNSUPPORTED_ERROR;
51004dcb 374 }
57a6839d 375 return;
51004dcb
A
376}
377
378
57a6839d
A
379
380U_DEPRECATED void U_EXPORT2
381u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
382 UErrorCode *status) {
383 if (U_SUCCESS(*status)) {
384 *status = U_UNSUPPORTED_ERROR;
385 }
386 return;
51004dcb 387}