• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Export an explicit template instantiation of std::atomic<int32_t>.
58 // When building DLLs for Windows this is required as it is used as a data member of the exported SharedObject class.
59 // See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.
60 #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN && !defined(U_IN_DOXYGEN)
61   #if defined(__clang__)
62   // Suppress the warning that the explicit instantiation after explicit specialization has no effect.
63   #pragma clang diagnostic push
64   #pragma clang diagnostic ignored "-Winstantiation-after-specialization"
65   #endif
66 template struct U_COMMON_API std::atomic<int32_t>;
67   #if defined(__clang__)
68   #pragma clang diagnostic pop
69   #endif
70 #endif
71 
72 U_NAMESPACE_BEGIN
73 
74 typedef std::atomic<int32_t> u_atomic_int32_t;
75 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
76 
77 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
78     return var.load(std::memory_order_acquire);
79 }
80 
81 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
82     var.store(val, std::memory_order_release);
83 }
84 
85 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
86     return var->fetch_add(1) + 1;
87 }
88 
89 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
90     return var->fetch_sub(1) - 1;
91 }
92 U_NAMESPACE_END
93 
94 #elif U_PLATFORM_HAS_WIN32_API
95 
96 // MSVC compiler. Reads and writes of volatile variables have
97 //                acquire and release memory semantics, respectively.
98 //                This is a Microsoft extension, not standard C++ behavior.
99 //
100 //   Update:      can't use this because of MinGW, built with gcc.
101 //                Original plan was to use gcc atomics for MinGW, but they
102 //                aren't supported, so we fold MinGW into this path.
103 
104 #ifndef WIN32_LEAN_AND_MEAN
105 # define WIN32_LEAN_AND_MEAN
106 #endif
107 # define VC_EXTRALEAN
108 # define NOUSER
109 # define NOSERVICE
110 # define NOIME
111 # define NOMCX
112 # ifndef NOMINMAX
113 # define NOMINMAX
114 # endif
115 # include <windows.h>
116 
117 U_NAMESPACE_BEGIN
118 typedef volatile LONG u_atomic_int32_t;
119 #define ATOMIC_INT32_T_INITIALIZER(val) val
120 
121 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
122     return InterlockedCompareExchange(&var, 0, 0);
123 }
124 
125 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
126     InterlockedExchange(&var, val);
127 }
128 
129 
130 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
131     return InterlockedIncrement(var);
132 }
133 
134 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
135     return InterlockedDecrement(var);
136 }
137 U_NAMESPACE_END
138 
139 
140 #elif U_HAVE_CLANG_ATOMICS
141 /*
142  *  Clang __c11 atomic built-ins
143  */
144 
145 U_NAMESPACE_BEGIN
146 typedef _Atomic(int32_t) u_atomic_int32_t;
147 #define ATOMIC_INT32_T_INITIALIZER(val) val
148 
149 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
150      return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
151 }
152 
153 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
154    return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
155 }
156 
157 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
158     return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
159 }
160 
161 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
162     return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
163 }
164 U_NAMESPACE_END
165 
166 
167 #elif U_HAVE_GCC_ATOMICS
168 /*
169  * gcc atomic ops. These are available on several other compilers as well.
170  */
171 
172 U_NAMESPACE_BEGIN
173 typedef int32_t u_atomic_int32_t;
174 #define ATOMIC_INT32_T_INITIALIZER(val) val
175 
176 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
177     int32_t val = var;
178     __sync_synchronize();
179     return val;
180 }
181 
182 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
183     __sync_synchronize();
184     var = val;
185 }
186 
187 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
188    return __sync_add_and_fetch(p, 1);
189 }
190 
191 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
192    return __sync_sub_and_fetch(p, 1);
193 }
194 U_NAMESPACE_END
195 
196 #else
197 
198 /*
199  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
200  *                   Slow but correct.
201  */
202 
203 #define U_NO_PLATFORM_ATOMICS
204 
205 U_NAMESPACE_BEGIN
206 typedef int32_t u_atomic_int32_t;
207 #define ATOMIC_INT32_T_INITIALIZER(val) val
208 
209 U_COMMON_API int32_t U_EXPORT2
210 umtx_loadAcquire(u_atomic_int32_t &var);
211 
212 U_COMMON_API void U_EXPORT2
213 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
214 
215 U_COMMON_API int32_t U_EXPORT2
216 umtx_atomic_inc(u_atomic_int32_t *p);
217 
218 U_COMMON_API int32_t U_EXPORT2
219 umtx_atomic_dec(u_atomic_int32_t *p);
220 
221 U_NAMESPACE_END
222 
223 #endif  /* Low Level Atomic Ops Platform Chain */
224 
225 
226 
227 /*************************************************************************************************
228  *
229  *  UInitOnce Definitions.
230  *     These are platform neutral.
231  *
232  *************************************************************************************************/
233 
234 U_NAMESPACE_BEGIN
235 
236 struct UInitOnce {
237     u_atomic_int32_t   fState;
238     UErrorCode       fErrCode;
resetUInitOnce239     void reset() {fState = 0;};
isResetUInitOnce240     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
241 // Note: isReset() is used by service registration code.
242 //                 Thread safety of this usage needs review.
243 };
244 
245 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
246 
247 
248 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
249 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
250 
umtx_initOnce(UInitOnce & uio,T * obj,void (U_CALLCONV T::* fp)())251 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (U_CALLCONV T::*fp)()) {
252     if (umtx_loadAcquire(uio.fState) == 2) {
253         return;
254     }
255     if (umtx_initImplPreInit(uio)) {
256         (obj->*fp)();
257         umtx_initImplPostInit(uio);
258     }
259 }
260 
261 
262 // umtx_initOnce variant for plain functions, or static class functions.
263 //               No context parameter.
umtx_initOnce(UInitOnce & uio,void (U_CALLCONV * fp)())264 inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)()) {
265     if (umtx_loadAcquire(uio.fState) == 2) {
266         return;
267     }
268     if (umtx_initImplPreInit(uio)) {
269         (*fp)();
270         umtx_initImplPostInit(uio);
271     }
272 }
273 
274 // umtx_initOnce variant for plain functions, or static class functions.
275 //               With ErrorCode, No context parameter.
umtx_initOnce(UInitOnce & uio,void (U_CALLCONV * fp)(UErrorCode &),UErrorCode & errCode)276 inline void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(UErrorCode &), UErrorCode &errCode) {
277     if (U_FAILURE(errCode)) {
278         return;
279     }
280     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
281         // We run the initialization.
282         (*fp)(errCode);
283         uio.fErrCode = errCode;
284         umtx_initImplPostInit(uio);
285     } else {
286         // Someone else already ran the initialization.
287         if (U_FAILURE(uio.fErrCode)) {
288             errCode = uio.fErrCode;
289         }
290     }
291 }
292 
293 // umtx_initOnce variant for plain functions, or static class functions,
294 //               with a context parameter.
umtx_initOnce(UInitOnce & uio,void (U_CALLCONV * fp)(T),T context)295 template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T), T context) {
296     if (umtx_loadAcquire(uio.fState) == 2) {
297         return;
298     }
299     if (umtx_initImplPreInit(uio)) {
300         (*fp)(context);
301         umtx_initImplPostInit(uio);
302     }
303 }
304 
305 // umtx_initOnce variant for plain functions, or static class functions,
306 //               with a context parameter and an error code.
umtx_initOnce(UInitOnce & uio,void (U_CALLCONV * fp)(T,UErrorCode &),T context,UErrorCode & errCode)307 template<class T> void umtx_initOnce(UInitOnce &uio, void (U_CALLCONV *fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
308     if (U_FAILURE(errCode)) {
309         return;
310     }
311     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
312         // We run the initialization.
313         (*fp)(context, errCode);
314         uio.fErrCode = errCode;
315         umtx_initImplPostInit(uio);
316     } else {
317         // Someone else already ran the initialization.
318         if (U_FAILURE(uio.fErrCode)) {
319             errCode = uio.fErrCode;
320         }
321     }
322 }
323 
324 U_NAMESPACE_END
325 
326 
327 
328 /*************************************************************************************************
329  *
330  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
331  *         TODO:  Add a C++11 version.
332  *                Need to convert all mutex using files to C++ first.
333  *
334  *************************************************************************************************/
335 
336 #if defined(U_USER_MUTEX_H)
337 // #include "U_USER_MUTEX_H"
338 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
339 
340 #elif U_PLATFORM_USES_ONLY_WIN32_API
341 
342 /* For CRITICAL_SECTION */
343 
344 /*
345  *   Note: there is an earlier include of windows.h in this file, but it is in
346  *         different conditionals.
347  *         This one is needed if we are using C++11 for atomic ops, but
348  *         win32 APIs for Critical Sections.
349  */
350 
351 #ifndef WIN32_LEAN_AND_MEAN
352 # define WIN32_LEAN_AND_MEAN
353 #endif
354 # define VC_EXTRALEAN
355 # define NOUSER
356 # define NOSERVICE
357 # define NOIME
358 # define NOMCX
359 # ifndef NOMINMAX
360 # define NOMINMAX
361 # endif
362 # include <windows.h>
363 
364 
365 typedef struct UMutex {
366     icu::UInitOnce    fInitOnce;
367     CRITICAL_SECTION  fCS;
368 } UMutex;
369 
370 /* Initializer for a static UMUTEX. Deliberately contains no value for the
371  *  CRITICAL_SECTION.
372  */
373 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
374 
375 struct UConditionVar {
376     HANDLE           fEntryGate;
377     HANDLE           fExitGate;
378     int32_t          fWaitCount;
379 };
380 
381 #define U_CONDITION_INITIALIZER {NULL, NULL, 0}
382 
383 
384 
385 #elif U_PLATFORM_IMPLEMENTS_POSIX
386 
387 /*
388  *  POSIX platform
389  */
390 
391 #include <pthread.h>
392 
393 struct UMutex {
394     pthread_mutex_t  fMutex;
395 };
396 typedef struct UMutex UMutex;
397 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
398 
399 struct UConditionVar {
400     pthread_cond_t   fCondition;
401 };
402 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
403 
404 #else
405 
406 /*
407  *  Unknown platform type.
408  *      This is an error condition. ICU requires mutexes.
409  */
410 
411 #error Unknown Platform.
412 
413 #endif
414 
415 
416 
417 /**************************************************************************************
418  *
419  *  Mutex Implementation function declarations.
420  *     Declarations are platform neutral.
421  *     Implementations, in umutex.cpp, are platform specific.
422  *
423  ************************************************************************************/
424 
425 /* Lock a mutex.
426  * @param mutex The given mutex to be locked.  Pass NULL to specify
427  *              the global ICU mutex.  Recursive locks are an error
428  *              and may cause a deadlock on some platforms.
429  */
430 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
431 
432 /* Unlock a mutex.
433  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
434  *              the global ICU mutex.
435  */
436 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
437 
438 /*
439  * Wait on a condition variable.
440  * The calling thread will unlock the mutex and wait on the condition variable.
441  * The mutex must be locked by the calling thread when invoking this function.
442  *
443  * @param cond the condition variable to wait on.
444  * @param mutex the associated mutex.
445  */
446 
447 U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
448 
449 
450 /*
451  * Broadcast wakeup of all threads waiting on a Condition.
452  * The associated mutex must be locked by the calling thread when calling
453  * this function; this is a temporary ICU restriction.
454  *
455  * @param cond the condition variable.
456  */
457 U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
458 
459 /*
460  * Signal a condition variable, waking up one waiting thread.
461  * CAUTION: Do not use. Place holder only. Not implemented for Windows.
462  */
463 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
464 
465 #endif /* UMUTEX_H */
466 /*eof*/
467