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