|
1 /* |
|
2 ****************************************************************************** |
|
3 * |
|
4 * Copyright (C) 1997-2013, International Business Machines |
|
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 |
|
21 #include "umutex.h" |
|
22 |
|
23 #include "unicode/utypes.h" |
|
24 #include "uassert.h" |
|
25 #include "cmemory.h" |
|
26 #include "ucln_cmn.h" |
|
27 |
|
28 |
|
29 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer. |
|
30 static UMutex globalMutex = U_MUTEX_INITIALIZER; |
|
31 |
|
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 |
|
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) |
|
40 |
|
41 #elif U_PLATFORM_HAS_WIN32_API |
|
42 |
|
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 //------------------------------------------------------------------------------------------- |
|
51 |
|
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. |
|
55 #endif |
|
56 |
|
57 |
|
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. |
|
61 // |
|
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. |
|
65 // |
|
66 |
|
67 U_NAMESPACE_BEGIN |
|
68 |
|
69 U_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); |
|
94 } |
|
95 } |
|
96 } |
|
97 |
|
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. |
|
105 |
|
106 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) { |
|
107 umtx_storeRelease(uio.fState, 2); |
|
108 } |
|
109 |
|
110 U_NAMESPACE_END |
|
111 |
|
112 static void winMutexInit(CRITICAL_SECTION *cs) { |
|
113 InitializeCriticalSection(cs); |
|
114 return; |
|
115 } |
|
116 |
|
117 U_CAPI void U_EXPORT2 |
|
118 umtx_lock(UMutex *mutex) { |
|
119 if (mutex == NULL) { |
|
120 mutex = &globalMutex; |
|
121 } |
|
122 CRITICAL_SECTION *cs = &mutex->fCS; |
|
123 umtx_initOnce(mutex->fInitOnce, winMutexInit, cs); |
|
124 EnterCriticalSection(cs); |
|
125 } |
|
126 |
|
127 U_CAPI void U_EXPORT2 |
|
128 umtx_unlock(UMutex* mutex) |
|
129 { |
|
130 if (mutex == NULL) { |
|
131 mutex = &globalMutex; |
|
132 } |
|
133 LeaveCriticalSection(&mutex->fCS); |
|
134 } |
|
135 |
|
136 #elif U_PLATFORM_IMPLEMENTS_POSIX |
|
137 |
|
138 //------------------------------------------------------------------------------------------- |
|
139 // |
|
140 // POSIX specific definitions |
|
141 // |
|
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. |
|
149 |
|
150 U_CAPI void U_EXPORT2 |
|
151 umtx_lock(UMutex *mutex) { |
|
152 if (mutex == NULL) { |
|
153 mutex = &globalMutex; |
|
154 } |
|
155 int sysErr = pthread_mutex_lock(&mutex->fMutex); |
|
156 (void)sysErr; // Suppress unused variable warnings. |
|
157 U_ASSERT(sysErr == 0); |
|
158 } |
|
159 |
|
160 |
|
161 U_CAPI void U_EXPORT2 |
|
162 umtx_unlock(UMutex* mutex) |
|
163 { |
|
164 if (mutex == NULL) { |
|
165 mutex = &globalMutex; |
|
166 } |
|
167 int sysErr = pthread_mutex_unlock(&mutex->fMutex); |
|
168 (void)sysErr; // Suppress unused variable warnings. |
|
169 U_ASSERT(sysErr == 0); |
|
170 } |
|
171 |
|
172 U_NAMESPACE_BEGIN |
|
173 |
|
174 static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER; |
|
175 static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER; |
|
176 |
|
177 |
|
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 // |
|
186 U_COMMON_API UBool U_EXPORT2 |
|
187 umtx_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; |
|
203 } |
|
204 } |
|
205 |
|
206 |
|
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 |
|
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); |
|
220 } |
|
221 |
|
222 U_NAMESPACE_END |
|
223 |
|
224 // End of POSIX specific umutex implementation. |
|
225 |
|
226 #else // Platform #define chain. |
|
227 |
|
228 #error Unknown Platform |
|
229 |
|
230 #endif // Platform #define chain. |
|
231 |
|
232 |
|
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 //-------------------------------------------------------------------------------- |
|
242 |
|
243 #if defined U_NO_PLATFORM_ATOMICS |
|
244 static UMutex gIncDecMutex = U_MUTEX_INITIALIZER; |
|
245 |
|
246 U_NAMESPACE_BEGIN |
|
247 |
|
248 U_COMMON_API int32_t U_EXPORT2 |
|
249 umtx_atomic_inc(u_atomic_int32_t *p) { |
|
250 int32_t retVal; |
|
251 umtx_lock(&gIncDecMutex); |
|
252 retVal = ++(*p); |
|
253 umtx_unlock(&gIncDecMutex); |
|
254 return retVal; |
|
255 } |
|
256 |
|
257 |
|
258 U_COMMON_API int32_t U_EXPORT2 |
|
259 umtx_atomic_dec(u_atomic_int32_t *p) { |
|
260 int32_t retVal; |
|
261 umtx_lock(&gIncDecMutex); |
|
262 retVal = --(*p); |
|
263 umtx_unlock(&gIncDecMutex); |
|
264 return retVal; |
|
265 } |
|
266 |
|
267 U_COMMON_API int32_t U_EXPORT2 |
|
268 umtx_loadAcquire(u_atomic_int32_t &var) { |
|
269 int32_t val = var; |
|
270 umtx_lock(&gIncDecMutex); |
|
271 umtx_unlock(&gIncDecMutex); |
|
272 return val; |
|
273 } |
|
274 |
|
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); |
|
279 var = val; |
|
280 } |
|
281 |
|
282 U_NAMESPACE_END |
|
283 #endif |
|
284 |
|
285 //-------------------------------------------------------------------------- |
|
286 // |
|
287 // Deprecated functions for setting user mutexes. |
|
288 // |
|
289 //-------------------------------------------------------------------------- |
|
290 |
|
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; |
|
296 } |
|
297 return; |
|
298 } |
|
299 |
|
300 |
|
301 |
|
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; |
|
307 } |
|
308 return; |
|
309 } |