|
1 /* |
|
2 ********************************************************************** |
|
3 * Copyright (C) 1997-2013, International Business Machines |
|
4 * Corporation and others. All Rights Reserved. |
|
5 ********************************************************************** |
|
6 * |
|
7 * File UMUTEX.H |
|
8 * |
|
9 * Modification History: |
|
10 * |
|
11 * Date Name Description |
|
12 * 04/02/97 aliu Creation. |
|
13 * 04/07/99 srl rewrite - C interface, multiple mutices |
|
14 * 05/13/99 stephen Changed to umutex (from cmutex) |
|
15 ****************************************************************************** |
|
16 */ |
|
17 |
|
18 #ifndef UMUTEX_H |
|
19 #define UMUTEX_H |
|
20 |
|
21 #include "unicode/utypes.h" |
|
22 #include "unicode/uclean.h" |
|
23 #include "putilimp.h" |
|
24 |
|
25 |
|
26 |
|
27 // Forward Declarations. UMutex is not in the ICU namespace (yet) because |
|
28 // there are some remaining references from plain C. |
|
29 struct UMutex; |
|
30 |
|
31 U_NAMESPACE_BEGIN |
|
32 struct UInitOnce; |
|
33 U_NAMESPACE_END |
|
34 |
|
35 // Stringify macros, to allow #include of user supplied atomic & mutex files. |
|
36 #define U_MUTEX_STR(s) #s |
|
37 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s) |
|
38 |
|
39 /**************************************************************************** |
|
40 * |
|
41 * Low Level Atomic Operations. |
|
42 * Compiler dependent. Not operating system dependent. |
|
43 * |
|
44 ****************************************************************************/ |
|
45 #if defined (U_USER_ATOMICS_H) |
|
46 #include U_MUTEX_XSTR(U_USER_ATOMICS_H) |
|
47 |
|
48 #elif U_HAVE_STD_ATOMICS |
|
49 |
|
50 // C++11 atomics are available. |
|
51 |
|
52 #include <atomic> |
|
53 |
|
54 U_NAMESPACE_BEGIN |
|
55 |
|
56 typedef std::atomic<int32_t> u_atomic_int32_t; |
|
57 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val) |
|
58 |
|
59 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { |
|
60 return var.load(std::memory_order_acquire); |
|
61 } |
|
62 |
|
63 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { |
|
64 var.store(val, std::memory_order_release); |
|
65 } |
|
66 |
|
67 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { |
|
68 return var->fetch_add(1) + 1; |
|
69 } |
|
70 |
|
71 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { |
|
72 return var->fetch_sub(1) - 1; |
|
73 } |
|
74 U_NAMESPACE_END |
|
75 |
|
76 #elif U_PLATFORM_HAS_WIN32_API |
|
77 |
|
78 // MSVC compiler. Reads and writes of volatile variables have |
|
79 // acquire and release memory semantics, respectively. |
|
80 // This is a Microsoft extension, not standard C++ behavior. |
|
81 // |
|
82 // Update: can't use this because of MinGW, built with gcc. |
|
83 // Original plan was to use gcc atomics for MinGW, but they |
|
84 // aren't supported, so we fold MinGW into this path. |
|
85 |
|
86 # define WIN32_LEAN_AND_MEAN |
|
87 # define VC_EXTRALEAN |
|
88 # define NOUSER |
|
89 # define NOSERVICE |
|
90 # define NOIME |
|
91 # define NOMCX |
|
92 # ifndef NOMINMAX |
|
93 # define NOMINMAX |
|
94 # endif |
|
95 # include <windows.h> |
|
96 |
|
97 U_NAMESPACE_BEGIN |
|
98 typedef volatile LONG u_atomic_int32_t; |
|
99 #define ATOMIC_INT32_T_INITIALIZER(val) val |
|
100 |
|
101 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { |
|
102 return InterlockedCompareExchange(&var, 0, 0); |
|
103 } |
|
104 |
|
105 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { |
|
106 InterlockedExchange(&var, val); |
|
107 } |
|
108 |
|
109 |
|
110 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { |
|
111 return InterlockedIncrement(var); |
|
112 } |
|
113 |
|
114 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { |
|
115 return InterlockedDecrement(var); |
|
116 } |
|
117 U_NAMESPACE_END |
|
118 |
|
119 |
|
120 #elif U_HAVE_GCC_ATOMICS |
|
121 /* |
|
122 * gcc atomic ops. These are available on several other compilers as well. |
|
123 */ |
|
124 |
|
125 U_NAMESPACE_BEGIN |
|
126 typedef int32_t u_atomic_int32_t; |
|
127 #define ATOMIC_INT32_T_INITIALIZER(val) val |
|
128 |
|
129 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { |
|
130 int32_t val = var; |
|
131 __sync_synchronize(); |
|
132 return val; |
|
133 } |
|
134 |
|
135 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { |
|
136 __sync_synchronize(); |
|
137 var = val; |
|
138 } |
|
139 |
|
140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) { |
|
141 return __sync_add_and_fetch(p, 1); |
|
142 } |
|
143 |
|
144 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) { |
|
145 return __sync_sub_and_fetch(p, 1); |
|
146 } |
|
147 U_NAMESPACE_END |
|
148 |
|
149 #else |
|
150 |
|
151 /* |
|
152 * Unknown Platform. Use out-of-line functions, which in turn use mutexes. |
|
153 * Slow but correct. |
|
154 */ |
|
155 |
|
156 #define U_NO_PLATFORM_ATOMICS |
|
157 |
|
158 U_NAMESPACE_BEGIN |
|
159 typedef int32_t u_atomic_int32_t; |
|
160 #define ATOMIC_INT32_T_INITIALIZER(val) val |
|
161 |
|
162 U_COMMON_API int32_t U_EXPORT2 |
|
163 umtx_loadAcquire(u_atomic_int32_t &var); |
|
164 |
|
165 U_COMMON_API void U_EXPORT2 |
|
166 umtx_storeRelease(u_atomic_int32_t &var, int32_t val); |
|
167 |
|
168 U_COMMON_API int32_t U_EXPORT2 |
|
169 umtx_atomic_inc(u_atomic_int32_t *p); |
|
170 |
|
171 U_COMMON_API int32_t U_EXPORT2 |
|
172 umtx_atomic_dec(u_atomic_int32_t *p); |
|
173 |
|
174 U_NAMESPACE_END |
|
175 |
|
176 #endif /* Low Level Atomic Ops Platfrom Chain */ |
|
177 |
|
178 |
|
179 |
|
180 /************************************************************************************************* |
|
181 * |
|
182 * UInitOnce Definitions. |
|
183 * These are platform neutral. |
|
184 * |
|
185 *************************************************************************************************/ |
|
186 |
|
187 U_NAMESPACE_BEGIN |
|
188 |
|
189 struct UInitOnce { |
|
190 u_atomic_int32_t fState; |
|
191 UErrorCode fErrCode; |
|
192 void reset() {fState = 0;}; |
|
193 UBool isReset() {return umtx_loadAcquire(fState) == 0;}; |
|
194 // Note: isReset() is used by service registration code. |
|
195 // Thread safety of this usage needs review. |
|
196 }; |
|
197 |
|
198 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR} |
|
199 |
|
200 |
|
201 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &); |
|
202 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &); |
|
203 |
|
204 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) { |
|
205 if (umtx_loadAcquire(uio.fState) == 2) { |
|
206 return; |
|
207 } |
|
208 if (umtx_initImplPreInit(uio)) { |
|
209 (obj->*fp)(); |
|
210 umtx_initImplPostInit(uio); |
|
211 } |
|
212 } |
|
213 |
|
214 |
|
215 // umtx_initOnce variant for plain functions, or static class functions. |
|
216 // No context parameter. |
|
217 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) { |
|
218 if (umtx_loadAcquire(uio.fState) == 2) { |
|
219 return; |
|
220 } |
|
221 if (umtx_initImplPreInit(uio)) { |
|
222 (*fp)(); |
|
223 umtx_initImplPostInit(uio); |
|
224 } |
|
225 } |
|
226 |
|
227 // umtx_initOnce variant for plain functions, or static class functions. |
|
228 // With ErrorCode, No context parameter. |
|
229 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) { |
|
230 if (U_FAILURE(errCode)) { |
|
231 return; |
|
232 } |
|
233 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { |
|
234 // We run the initialization. |
|
235 (*fp)(errCode); |
|
236 uio.fErrCode = errCode; |
|
237 umtx_initImplPostInit(uio); |
|
238 } else { |
|
239 // Someone else already ran the initialization. |
|
240 if (U_FAILURE(uio.fErrCode)) { |
|
241 errCode = uio.fErrCode; |
|
242 } |
|
243 } |
|
244 } |
|
245 |
|
246 // umtx_initOnce variant for plain functions, or static class functions, |
|
247 // with a context parameter. |
|
248 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) { |
|
249 if (umtx_loadAcquire(uio.fState) == 2) { |
|
250 return; |
|
251 } |
|
252 if (umtx_initImplPreInit(uio)) { |
|
253 (*fp)(context); |
|
254 umtx_initImplPostInit(uio); |
|
255 } |
|
256 } |
|
257 |
|
258 // umtx_initOnce variant for plain functions, or static class functions, |
|
259 // with a context parameter and an error code. |
|
260 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) { |
|
261 if (U_FAILURE(errCode)) { |
|
262 return; |
|
263 } |
|
264 if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { |
|
265 // We run the initialization. |
|
266 (*fp)(context, errCode); |
|
267 uio.fErrCode = errCode; |
|
268 umtx_initImplPostInit(uio); |
|
269 } else { |
|
270 // Someone else already ran the initialization. |
|
271 if (U_FAILURE(uio.fErrCode)) { |
|
272 errCode = uio.fErrCode; |
|
273 } |
|
274 } |
|
275 } |
|
276 |
|
277 U_NAMESPACE_END |
|
278 |
|
279 |
|
280 |
|
281 /************************************************************************************************* |
|
282 * |
|
283 * Mutex Definitions. Platform Dependent, #if platform chain follows. |
|
284 * TODO: Add a C++11 version. |
|
285 * Need to convert all mutex using files to C++ first. |
|
286 * |
|
287 *************************************************************************************************/ |
|
288 |
|
289 #if defined(U_USER_MUTEX_H) |
|
290 // #inlcude "U_USER_MUTEX_H" |
|
291 #include U_MUTEX_XSTR(U_USER_MUTEX_H) |
|
292 |
|
293 #elif U_PLATFORM_HAS_WIN32_API |
|
294 |
|
295 /* Windows Definitions. |
|
296 * Windows comes first in the platform chain. |
|
297 * Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case. |
|
298 */ |
|
299 |
|
300 |
|
301 /* For CRITICAL_SECTION */ |
|
302 |
|
303 /* |
|
304 * Note: there is an earlier include of windows.h in this file, but it is in |
|
305 * different conditionals. |
|
306 * This one is needed if we are using C++11 for atomic ops, but |
|
307 * win32 APIs for Critical Sections. |
|
308 */ |
|
309 |
|
310 # define WIN32_LEAN_AND_MEAN |
|
311 # define VC_EXTRALEAN |
|
312 # define NOUSER |
|
313 # define NOSERVICE |
|
314 # define NOIME |
|
315 # define NOMCX |
|
316 # ifndef NOMINMAX |
|
317 # define NOMINMAX |
|
318 # endif |
|
319 # include <windows.h> |
|
320 |
|
321 |
|
322 typedef struct UMutex { |
|
323 icu::UInitOnce fInitOnce; |
|
324 CRITICAL_SECTION fCS; |
|
325 } UMutex; |
|
326 |
|
327 /* Initializer for a static UMUTEX. Deliberately contains no value for the |
|
328 * CRITICAL_SECTION. |
|
329 */ |
|
330 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER} |
|
331 |
|
332 |
|
333 |
|
334 #elif U_PLATFORM_IMPLEMENTS_POSIX |
|
335 |
|
336 /* |
|
337 * POSIX platform |
|
338 */ |
|
339 |
|
340 #include <pthread.h> |
|
341 |
|
342 struct UMutex { |
|
343 pthread_mutex_t fMutex; |
|
344 }; |
|
345 typedef struct UMutex UMutex; |
|
346 #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER} |
|
347 |
|
348 #else |
|
349 |
|
350 /* |
|
351 * Unknow platform type. |
|
352 * This is an error condition. ICU requires mutexes. |
|
353 */ |
|
354 |
|
355 #error Unknown Platform. |
|
356 |
|
357 #endif |
|
358 |
|
359 |
|
360 |
|
361 /************************************************************************************** |
|
362 * |
|
363 * Mutex Implementation function declaratations. |
|
364 * Declarations are platform neutral. |
|
365 * Implementations, in umutex.cpp, are platform specific. |
|
366 * |
|
367 ************************************************************************************/ |
|
368 |
|
369 /* Lock a mutex. |
|
370 * @param mutex The given mutex to be locked. Pass NULL to specify |
|
371 * the global ICU mutex. Recursive locks are an error |
|
372 * and may cause a deadlock on some platforms. |
|
373 */ |
|
374 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex); |
|
375 |
|
376 /* Unlock a mutex. |
|
377 * @param mutex The given mutex to be unlocked. Pass NULL to specify |
|
378 * the global ICU mutex. |
|
379 */ |
|
380 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); |
|
381 |
|
382 #endif /* UMUTEX_H */ |
|
383 /*eof*/ |