]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.cpp
ICU-531.48.tar.gz
[apple/icu.git] / icuSources / common / umutex.cpp
CommitLineData
51004dcb
A
1/*
2******************************************************************************
3*
57a6839d 4* Copyright (C) 1997-2013, 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
A
26#include "ucln_cmn.h"
27
57a6839d
A
28
29// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
30static UMutex globalMutex = U_MUTEX_INITIALIZER;
31
51004dcb
A
32/*
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.
35 */
36
57a6839d
A
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)
51004dcb 40
57a6839d 41#elif U_PLATFORM_HAS_WIN32_API
51004dcb 42
57a6839d
A
43//-------------------------------------------------------------------------------------------
44//
45// Windows Specific Definitions
46//
47// Note: Cygwin (and possibly others) have both WIN32 and POSIX.
48// Prefer Win32 in these cases. (Win32 comes ahead in the #if chain)
49//
50//-------------------------------------------------------------------------------------------
51004dcb 51
57a6839d
A
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.
51004dcb
A
55#endif
56
51004dcb 57
57a6839d
A
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.
51004dcb 61//
57a6839d
A
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.
51004dcb 65//
51004dcb 66
57a6839d 67U_NAMESPACE_BEGIN
51004dcb 68
57a6839d
A
69U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
70 for (;;) {
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.
74#endif
75 &uio.fState, // Destination
76 1, // Exchange Value
77 0); // Compare value
78
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.
86 return FALSE;
87 } else {
88 // Another thread is currently running the initialization.
89 // Wait until it completes.
90 do {
91 Sleep(1);
92 previousState = umtx_loadAcquire(uio.fState);
93 } while (previousState == 1);
51004dcb 94 }
51004dcb 95 }
51004dcb
A
96}
97
57a6839d
A
98// This function is called by the thread that ran an initialization function,
99// just after completing the function.
100//
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.
51004dcb 105
57a6839d
A
106U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
107 umtx_storeRelease(uio.fState, 2);
51004dcb 108}
51004dcb 109
57a6839d 110U_NAMESPACE_END
51004dcb 111
57a6839d
A
112static void winMutexInit(CRITICAL_SECTION *cs) {
113 InitializeCriticalSection(cs);
114 return;
115}
51004dcb
A
116
117U_CAPI void U_EXPORT2
118umtx_lock(UMutex *mutex) {
119 if (mutex == NULL) {
120 mutex = &globalMutex;
121 }
57a6839d
A
122 CRITICAL_SECTION *cs = &mutex->fCS;
123 umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
124 EnterCriticalSection(cs);
51004dcb
A
125}
126
51004dcb
A
127U_CAPI void U_EXPORT2
128umtx_unlock(UMutex* mutex)
129{
130 if (mutex == NULL) {
131 mutex = &globalMutex;
132 }
57a6839d 133 LeaveCriticalSection(&mutex->fCS);
51004dcb
A
134}
135
57a6839d
A
136#elif U_PLATFORM_IMPLEMENTS_POSIX
137
138//-------------------------------------------------------------------------------------------
51004dcb 139//
57a6839d 140// POSIX specific definitions
51004dcb 141//
57a6839d
A
142//-------------------------------------------------------------------------------------------
143
144# include <pthread.h>
145
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.
51004dcb 149
51004dcb
A
150U_CAPI void U_EXPORT2
151umtx_lock(UMutex *mutex) {
152 if (mutex == NULL) {
153 mutex = &globalMutex;
154 }
57a6839d
A
155 int sysErr = pthread_mutex_lock(&mutex->fMutex);
156 (void)sysErr; // Suppress unused variable warnings.
157 U_ASSERT(sysErr == 0);
51004dcb
A
158}
159
57a6839d 160
51004dcb
A
161U_CAPI void U_EXPORT2
162umtx_unlock(UMutex* mutex)
163{
164 if (mutex == NULL) {
165 mutex = &globalMutex;
166 }
57a6839d
A
167 int sysErr = pthread_mutex_unlock(&mutex->fMutex);
168 (void)sysErr; // Suppress unused variable warnings.
169 U_ASSERT(sysErr == 0);
51004dcb
A
170}
171
57a6839d 172U_NAMESPACE_BEGIN
51004dcb 173
57a6839d
A
174static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
175static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
51004dcb 176
51004dcb 177
57a6839d
A
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.
181//
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.
185//
186U_COMMON_API UBool U_EXPORT2
187umtx_initImplPreInit(UInitOnce &uio) {
188 pthread_mutex_lock(&initMutex);
189 int32_t state = uio.fState;
190 if (state == 0) {
191 umtx_storeRelease(uio.fState, 1);
192 pthread_mutex_unlock(&initMutex);
193 return TRUE; // Caller will next call the init function.
194 } else {
195 while (uio.fState == 1) {
196 // Another thread is currently running the initialization.
197 // Wait until it completes.
198 pthread_cond_wait(&initCondition, &initMutex);
199 }
200 pthread_mutex_unlock(&initMutex);
201 U_ASSERT(uio.fState == 2);
202 return FALSE;
51004dcb 203 }
57a6839d 204}
51004dcb 205
51004dcb 206
57a6839d
A
207
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.
213
214U_COMMON_API void U_EXPORT2
215umtx_initImplPostInit(UInitOnce &uio) {
216 pthread_mutex_lock(&initMutex);
217 umtx_storeRelease(uio.fState, 2);
218 pthread_cond_broadcast(&initCondition);
219 pthread_mutex_unlock(&initMutex);
51004dcb
A
220}
221
57a6839d 222U_NAMESPACE_END
51004dcb 223
57a6839d 224// End of POSIX specific umutex implementation.
51004dcb 225
57a6839d 226#else // Platform #define chain.
51004dcb 227
57a6839d 228#error Unknown Platform
51004dcb 229
57a6839d 230#endif // Platform #define chain.
51004dcb 231
51004dcb 232
57a6839d
A
233//-------------------------------------------------------------------------------
234//
235// Atomic Operations, out-of-line versions.
236// These are conditional, only defined if better versions
237// were not available for the platform.
238//
239// These versions are platform neutral.
240//
241//--------------------------------------------------------------------------------
51004dcb 242
57a6839d 243#if defined U_NO_PLATFORM_ATOMICS
51004dcb 244static UMutex gIncDecMutex = U_MUTEX_INITIALIZER;
51004dcb 245
57a6839d
A
246U_NAMESPACE_BEGIN
247
248U_COMMON_API int32_t U_EXPORT2
249umtx_atomic_inc(u_atomic_int32_t *p) {
51004dcb 250 int32_t retVal;
57a6839d
A
251 umtx_lock(&gIncDecMutex);
252 retVal = ++(*p);
253 umtx_unlock(&gIncDecMutex);
51004dcb
A
254 return retVal;
255}
256
57a6839d
A
257
258U_COMMON_API int32_t U_EXPORT2
259umtx_atomic_dec(u_atomic_int32_t *p) {
51004dcb 260 int32_t retVal;
57a6839d
A
261 umtx_lock(&gIncDecMutex);
262 retVal = --(*p);
263 umtx_unlock(&gIncDecMutex);
51004dcb
A
264 return retVal;
265}
266
57a6839d
A
267U_COMMON_API int32_t U_EXPORT2
268umtx_loadAcquire(u_atomic_int32_t &var) {
269 int32_t val = var;
270 umtx_lock(&gIncDecMutex);
271 umtx_unlock(&gIncDecMutex);
272 return val;
273}
274
275U_COMMON_API void U_EXPORT2
276umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
277 umtx_lock(&gIncDecMutex);
278 umtx_unlock(&gIncDecMutex);
279 var = val;
280}
51004dcb 281
57a6839d
A
282U_NAMESPACE_END
283#endif
51004dcb 284
57a6839d
A
285//--------------------------------------------------------------------------
286//
287// Deprecated functions for setting user mutexes.
288//
289//--------------------------------------------------------------------------
51004dcb 290
57a6839d
A
291U_DEPRECATED void U_EXPORT2
292u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
293 UMtxFn *, UMtxFn *, UErrorCode *status) {
294 if (U_SUCCESS(*status)) {
295 *status = U_UNSUPPORTED_ERROR;
51004dcb 296 }
57a6839d 297 return;
51004dcb
A
298}
299
300
57a6839d
A
301
302U_DEPRECATED void U_EXPORT2
303u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
304 UErrorCode *status) {
305 if (U_SUCCESS(*status)) {
306 *status = U_UNSUPPORTED_ERROR;
307 }
308 return;
51004dcb 309}