Line data Source code
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 : 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 :
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 34 : inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
162 34 : int32_t val = var;
163 34 : __sync_synchronize();
164 34 : return val;
165 : }
166 :
167 33 : inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
168 33 : __sync_synchronize();
169 33 : var = val;
170 33 : }
171 :
172 0 : inline int32_t umtx_atomic_inc(u_atomic_int32_t *p) {
173 0 : return __sync_add_and_fetch(p, 1);
174 : }
175 :
176 0 : inline int32_t umtx_atomic_dec(u_atomic_int32_t *p) {
177 0 : 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 5 : 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 10 : inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
250 10 : if (umtx_loadAcquire(uio.fState) == 2) {
251 7 : return;
252 : }
253 3 : if (umtx_initImplPreInit(uio)) {
254 3 : (*fp)();
255 3 : umtx_initImplPostInit(uio);
256 : }
257 : }
258 :
259 : // umtx_initOnce variant for plain functions, or static class functions.
260 : // With ErrorCode, No context parameter.
261 21 : inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
262 21 : if (U_FAILURE(errCode)) {
263 0 : return;
264 : }
265 21 : if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
266 : // We run the initialization.
267 12 : (*fp)(errCode);
268 12 : uio.fErrCode = errCode;
269 12 : umtx_initImplPostInit(uio);
270 : } else {
271 : // Someone else already ran the initialization.
272 9 : if (U_FAILURE(uio.fErrCode)) {
273 0 : errCode = uio.fErrCode;
274 : }
275 : }
276 : }
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 : }
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 : } else {
302 : // Someone else already ran the initialization.
303 0 : if (U_FAILURE(uio.fErrCode)) {
304 0 : errCode = uio.fErrCode;
305 : }
306 : }
307 : }
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*/
|