/src/icu/source/common/umutex.h
Line | Count | Source (jump to first uncovered line) |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | /* |
4 | | ********************************************************************** |
5 | | * Copyright (C) 1997-2015, International Business Machines |
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" |
24 | | #include "unicode/uclean.h" |
25 | | #include "putilimp.h" |
26 | | |
27 | | |
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; |
32 | | struct UConditionVar; |
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 | 7.86k | inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { |
63 | 7.86k | return var.load(std::memory_order_acquire); |
64 | 7.86k | } |
65 | | |
66 | 4.46k | inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) { |
67 | 4.46k | var.store(val, std::memory_order_release); |
68 | 4.46k | } |
69 | | |
70 | 0 | inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) { |
71 | 0 | return var->fetch_add(1) + 1; |
72 | 0 | } |
73 | | |
74 | 5.27M | inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) { |
75 | 5.27M | return var->fetch_sub(1) - 1; |
76 | 5.27M | } |
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 | | |
89 | | #ifndef WIN32_LEAN_AND_MEAN |
90 | | # define WIN32_LEAN_AND_MEAN |
91 | | #endif |
92 | | # define VC_EXTRALEAN |
93 | | # define NOUSER |
94 | | # define NOSERVICE |
95 | | # define NOIME |
96 | | # define NOMCX |
97 | | # ifndef NOMINMAX |
98 | | # define NOMINMAX |
99 | | # endif |
100 | | # include <windows.h> |
101 | | |
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 | | |
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 | | |
152 | | #elif U_HAVE_GCC_ATOMICS |
153 | | /* |
154 | | * gcc atomic ops. These are available on several other compilers as well. |
155 | | */ |
156 | | |
157 | | U_NAMESPACE_BEGIN |
158 | | typedef int32_t u_atomic_int32_t; |
159 | | #define ATOMIC_INT32_T_INITIALIZER(val) val |
160 | | |
161 | | inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) { |
162 | | int32_t val = var; |
163 | | __sync_synchronize(); |
164 | | return val; |
165 | | } |
166 | | |
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 |
182 | | |
183 | | /* |
184 | | * Unknown Platform. Use out-of-line functions, which in turn use mutexes. |
185 | | * Slow but correct. |
186 | | */ |
187 | | |
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 | | /************************************************************************************************* |
213 | | * |
214 | | * UInitOnce Definitions. |
215 | | * These are platform neutral. |
216 | | * |
217 | | *************************************************************************************************/ |
218 | | |
219 | | U_NAMESPACE_BEGIN |
220 | | |
221 | | struct UInitOnce { |
222 | | u_atomic_int32_t fState; |
223 | | UErrorCode fErrCode; |
224 | 6.69k | void reset() {fState = 0;}; |
225 | 0 | 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 | | |
236 | | template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) { |
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. |
249 | 1.11k | inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) { |
250 | 1.11k | if (umtx_loadAcquire(uio.fState) == 2) { |
251 | 0 | return; |
252 | 0 | } |
253 | 1.11k | if (umtx_initImplPreInit(uio)) { |
254 | 1.11k | (*fp)(); |
255 | 1.11k | umtx_initImplPostInit(uio); |
256 | 1.11k | } |
257 | 1.11k | } |
258 | | |
259 | | // umtx_initOnce variant for plain functions, or static class functions. |
260 | | // With ErrorCode, No context parameter. |
261 | 2.23k | inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) { |
262 | 2.23k | if (U_FAILURE(errCode)) { |
263 | 0 | return; |
264 | 0 | } |
265 | 2.23k | if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { |
266 | | // We run the initialization. |
267 | 1.11k | (*fp)(errCode); |
268 | 1.11k | uio.fErrCode = errCode; |
269 | 1.11k | umtx_initImplPostInit(uio); |
270 | 1.11k | } else { |
271 | | // Someone else already ran the initialization. |
272 | 1.11k | if (U_FAILURE(uio.fErrCode)) { |
273 | 0 | errCode = uio.fErrCode; |
274 | 0 | } |
275 | 1.11k | } |
276 | 2.23k | } |
277 | | |
278 | | // umtx_initOnce variant for plain functions, or static class functions, |
279 | | // with a context parameter. |
280 | | template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) { |
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. |
292 | 0 | template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) { |
293 | 0 | if (U_FAILURE(errCode)) { |
294 | 0 | return; |
295 | 0 | } |
296 | 0 | if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) { |
297 | | // We run the initialization. |
298 | 0 | (*fp)(context, errCode); |
299 | 0 | uio.fErrCode = errCode; |
300 | 0 | umtx_initImplPostInit(uio); |
301 | 0 | } else { |
302 | | // Someone else already ran the initialization. |
303 | 0 | if (U_FAILURE(uio.fErrCode)) { |
304 | 0 | errCode = uio.fErrCode; |
305 | 0 | } |
306 | 0 | } |
307 | 0 | } Unexecuted instantiation: void icu_59::umtx_initOnce<char const*>(icu_59::UInitOnce&, void (*)(char const*, UErrorCode&), char const*, UErrorCode&) Unexecuted instantiation: void icu_59::umtx_initOnce<icu_59::Normalizer2Impl*>(icu_59::UInitOnce&, void (*)(icu_59::Normalizer2Impl*, UErrorCode&), icu_59::Normalizer2Impl*, UErrorCode&) |
308 | | |
309 | | U_NAMESPACE_END |
310 | | |
311 | | |
312 | | |
313 | | /************************************************************************************************* |
314 | | * |
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 | | *************************************************************************************************/ |
320 | | |
321 | | #if defined(U_USER_MUTEX_H) |
322 | | // #inlcude "U_USER_MUTEX_H" |
323 | | #include U_MUTEX_XSTR(U_USER_MUTEX_H) |
324 | | |
325 | | #elif U_PLATFORM_USES_ONLY_WIN32_API |
326 | | |
327 | | /* For CRITICAL_SECTION */ |
328 | | |
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. |
334 | | */ |
335 | | |
336 | | #ifndef WIN32_LEAN_AND_MEAN |
337 | | # define WIN32_LEAN_AND_MEAN |
338 | | #endif |
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 | | |
349 | | |
350 | | typedef struct UMutex { |
351 | | icu::UInitOnce fInitOnce; |
352 | | CRITICAL_SECTION fCS; |
353 | | } UMutex; |
354 | | |
355 | | /* Initializer for a static UMUTEX. Deliberately contains no value for the |
356 | | * CRITICAL_SECTION. |
357 | | */ |
358 | | #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER} |
359 | | |
360 | | struct UConditionVar { |
361 | | HANDLE fEntryGate; |
362 | | HANDLE fExitGate; |
363 | | int32_t fWaitCount; |
364 | | }; |
365 | | |
366 | | #define U_CONDITION_INITIALIZER {NULL, NULL, 0} |
367 | | |
368 | | |
369 | | |
370 | | #elif U_PLATFORM_IMPLEMENTS_POSIX |
371 | | |
372 | | /* |
373 | | * POSIX platform |
374 | | */ |
375 | | |
376 | | #include <pthread.h> |
377 | | |
378 | | struct UMutex { |
379 | | pthread_mutex_t fMutex; |
380 | | }; |
381 | | typedef struct UMutex UMutex; |
382 | | #define U_MUTEX_INITIALIZER {PTHREAD_MUTEX_INITIALIZER} |
383 | | |
384 | | struct UConditionVar { |
385 | | pthread_cond_t fCondition; |
386 | | }; |
387 | | #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER} |
388 | | |
389 | | #else |
390 | | |
391 | | /* |
392 | | * Unknow platform type. |
393 | | * This is an error condition. ICU requires mutexes. |
394 | | */ |
395 | | |
396 | | #error Unknown Platform. |
397 | | |
398 | | #endif |
399 | | |
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 | | |
410 | | /* Lock a mutex. |
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. |
414 | | */ |
415 | | U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex); |
416 | | |
417 | | /* Unlock a mutex. |
418 | | * @param mutex The given mutex to be unlocked. Pass NULL to specify |
419 | | * the global ICU mutex. |
420 | | */ |
421 | | U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex); |
422 | | |
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 | | |
450 | | #endif /* UMUTEX_H */ |
451 | | /*eof*/ |