• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **********************************************************************
3 *   Copyright (C) 1997-2015, 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 struct UConditionVar;
31 
32 U_NAMESPACE_BEGIN
33 struct UInitOnce;
34 U_NAMESPACE_END
35 
36 // Stringify macros, to allow #include of user supplied atomic & mutex files.
37 #define U_MUTEX_STR(s) #s
38 #define U_MUTEX_XSTR(s) U_MUTEX_STR(s)
39 
40 /****************************************************************************
41  *
42  *   Low Level Atomic Operations.
43  *      Compiler dependent. Not operating system dependent.
44  *
45  ****************************************************************************/
46 #if defined (U_USER_ATOMICS_H)
47 #include U_MUTEX_XSTR(U_USER_ATOMICS_H)
48 
49 #elif U_HAVE_STD_ATOMICS
50 
51 //  C++11 atomics are available.
52 
53 #include <atomic>
54 
55 U_NAMESPACE_BEGIN
56 
57 typedef std::atomic<int32_t> u_atomic_int32_t;
58 #define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
59 
60 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
61     return var.load(std::memory_order_acquire);
62 }
63 
64 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
65     var.store(val, std::memory_order_release);
66 }
67 
68 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
69     return var->fetch_add(1) + 1;
70 }
71 
72 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
73     return var->fetch_sub(1) - 1;
74 }
75 U_NAMESPACE_END
76 
77 #elif U_PLATFORM_HAS_WIN32_API
78 
79 // MSVC compiler. Reads and writes of volatile variables have
80 //                acquire and release memory semantics, respectively.
81 //                This is a Microsoft extension, not standard C++ behavior.
82 //
83 //   Update:      can't use this because of MinGW, built with gcc.
84 //                Original plan was to use gcc atomics for MinGW, but they
85 //                aren't supported, so we fold MinGW into this path.
86 
87 # define WIN32_LEAN_AND_MEAN
88 # define VC_EXTRALEAN
89 # define NOUSER
90 # define NOSERVICE
91 # define NOIME
92 # define NOMCX
93 # ifndef NOMINMAX
94 # define NOMINMAX
95 # endif
96 # include <windows.h>
97 
98 U_NAMESPACE_BEGIN
99 typedef volatile LONG u_atomic_int32_t;
100 #define ATOMIC_INT32_T_INITIALIZER(val) val
101 
102 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
103     return InterlockedCompareExchange(&var, 0, 0);
104 }
105 
106 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
107     InterlockedExchange(&var, val);
108 }
109 
110 
111 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
112     return InterlockedIncrement(var);
113 }
114 
115 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
116     return InterlockedDecrement(var);
117 }
118 U_NAMESPACE_END
119 
120 
121 #elif U_HAVE_CLANG_ATOMICS
122 /*
123  *  Clang __c11 atomic built-ins
124  */
125 
126 U_NAMESPACE_BEGIN
127 typedef _Atomic(int32_t) u_atomic_int32_t;
128 #define ATOMIC_INT32_T_INITIALIZER(val) val
129 
130 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
131      return __c11_atomic_load(&var, __ATOMIC_ACQUIRE);
132 }
133 
134 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
135    return __c11_atomic_store(&var, val, __ATOMIC_RELEASE);
136 }
137 
138 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
139     return __c11_atomic_fetch_add(var, 1, __ATOMIC_SEQ_CST) + 1;
140 }
141 
142 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
143     return __c11_atomic_fetch_sub(var, 1, __ATOMIC_SEQ_CST) - 1;
144 }
145 U_NAMESPACE_END
146 
147 
148 #elif U_HAVE_GCC_ATOMICS
149 /*
150  * gcc atomic ops. These are available on several other compilers as well.
151  */
152 
153 U_NAMESPACE_BEGIN
154 typedef int32_t u_atomic_int32_t;
155 #define ATOMIC_INT32_T_INITIALIZER(val) val
156 
157 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
158     int32_t val = var;
159     __sync_synchronize();
160     return val;
161 }
162 
163 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
164     __sync_synchronize();
165     var = val;
166 }
167 
168 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
169    return __sync_add_and_fetch(p, 1);
170 }
171 
172 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
173    return __sync_sub_and_fetch(p, 1);
174 }
175 U_NAMESPACE_END
176 
177 #else
178 
179 /*
180  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
181  *                   Slow but correct.
182  */
183 
184 #define U_NO_PLATFORM_ATOMICS
185 
186 U_NAMESPACE_BEGIN
187 typedef int32_t u_atomic_int32_t;
188 #define ATOMIC_INT32_T_INITIALIZER(val) val
189 
190 U_COMMON_API int32_t U_EXPORT2
191 umtx_loadAcquire(u_atomic_int32_t &var);
192 
193 U_COMMON_API void U_EXPORT2
194 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
195 
196 U_COMMON_API int32_t U_EXPORT2
197 umtx_atomic_inc(u_atomic_int32_t *p);
198 
199 U_COMMON_API int32_t U_EXPORT2
200 umtx_atomic_dec(u_atomic_int32_t *p);
201 
202 U_NAMESPACE_END
203 
204 #endif  /* Low Level Atomic Ops Platfrom Chain */
205 
206 
207 
208 /*************************************************************************************************
209  *
210  *  UInitOnce Definitions.
211  *     These are platform neutral.
212  *
213  *************************************************************************************************/
214 
215 U_NAMESPACE_BEGIN
216 
217 struct UInitOnce {
218     u_atomic_int32_t   fState;
219     UErrorCode       fErrCode;
resetUInitOnce220     void reset() {fState = 0;};
isResetUInitOnce221     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
222 // Note: isReset() is used by service registration code.
223 //                 Thread safety of this usage needs review.
224 };
225 
226 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
227 
228 
229 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
230 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
231 
umtx_initOnce(UInitOnce & uio,T * obj,void (T::* fp)())232 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
233     if (umtx_loadAcquire(uio.fState) == 2) {
234         return;
235     }
236     if (umtx_initImplPreInit(uio)) {
237         (obj->*fp)();
238         umtx_initImplPostInit(uio);
239     }
240 }
241 
242 
243 // umtx_initOnce variant for plain functions, or static class functions.
244 //               No context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)())245 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
246     if (umtx_loadAcquire(uio.fState) == 2) {
247         return;
248     }
249     if (umtx_initImplPreInit(uio)) {
250         (*fp)();
251         umtx_initImplPostInit(uio);
252     }
253 }
254 
255 // umtx_initOnce variant for plain functions, or static class functions.
256 //               With ErrorCode, No context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)(UErrorCode &),UErrorCode & errCode)257 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
258     if (U_FAILURE(errCode)) {
259         return;
260     }
261     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
262         // We run the initialization.
263         (*fp)(errCode);
264         uio.fErrCode = errCode;
265         umtx_initImplPostInit(uio);
266     } else {
267         // Someone else already ran the initialization.
268         if (U_FAILURE(uio.fErrCode)) {
269             errCode = uio.fErrCode;
270         }
271     }
272 }
273 
274 // umtx_initOnce variant for plain functions, or static class functions,
275 //               with a context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)(T),T context)276 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
277     if (umtx_loadAcquire(uio.fState) == 2) {
278         return;
279     }
280     if (umtx_initImplPreInit(uio)) {
281         (*fp)(context);
282         umtx_initImplPostInit(uio);
283     }
284 }
285 
286 // umtx_initOnce variant for plain functions, or static class functions,
287 //               with a context parameter and an error code.
umtx_initOnce(UInitOnce & uio,void (* fp)(T,UErrorCode &),T context,UErrorCode & errCode)288 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
289     if (U_FAILURE(errCode)) {
290         return;
291     }
292     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
293         // We run the initialization.
294         (*fp)(context, errCode);
295         uio.fErrCode = errCode;
296         umtx_initImplPostInit(uio);
297     } else {
298         // Someone else already ran the initialization.
299         if (U_FAILURE(uio.fErrCode)) {
300             errCode = uio.fErrCode;
301         }
302     }
303 }
304 
305 U_NAMESPACE_END
306 
307 
308 
309 /*************************************************************************************************
310  *
311  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
312  *         TODO:  Add a C++11 version.
313  *                Need to convert all mutex using files to C++ first.
314  *
315  *************************************************************************************************/
316 
317 #if defined(U_USER_MUTEX_H)
318 // #inlcude "U_USER_MUTEX_H"
319 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
320 
321 #elif U_PLATFORM_HAS_WIN32_API
322 
323 /* Windows Definitions.
324  *    Windows comes first in the platform chain.
325  *    Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
326  */
327 
328 
329 /* For CRITICAL_SECTION */
330 
331 /*
332  *   Note: there is an earlier include of windows.h in this file, but it is in
333  *         different conditionals.
334  *         This one is needed if we are using C++11 for atomic ops, but
335  *         win32 APIs for Critical Sections.
336  */
337 
338 # define WIN32_LEAN_AND_MEAN
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*/
452