• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **********************************************************************
3 *   Copyright (C) 1997-2014, 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_GCC_ATOMICS
122 /*
123  * gcc atomic ops. These are available on several other compilers as well.
124  */
125 
126 U_NAMESPACE_BEGIN
127 typedef 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     int32_t val = var;
132     __sync_synchronize();
133     return val;
134 }
135 
136 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
137     __sync_synchronize();
138     var = val;
139 }
140 
141 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
142    return __sync_add_and_fetch(p, 1);
143 }
144 
145 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
146    return __sync_sub_and_fetch(p, 1);
147 }
148 U_NAMESPACE_END
149 
150 #else
151 
152 /*
153  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
154  *                   Slow but correct.
155  */
156 
157 #define U_NO_PLATFORM_ATOMICS
158 
159 U_NAMESPACE_BEGIN
160 typedef int32_t u_atomic_int32_t;
161 #define ATOMIC_INT32_T_INITIALIZER(val) val
162 
163 U_COMMON_API int32_t U_EXPORT2
164 umtx_loadAcquire(u_atomic_int32_t &var);
165 
166 U_COMMON_API void U_EXPORT2
167 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
168 
169 U_COMMON_API int32_t U_EXPORT2
170 umtx_atomic_inc(u_atomic_int32_t *p);
171 
172 U_COMMON_API int32_t U_EXPORT2
173 umtx_atomic_dec(u_atomic_int32_t *p);
174 
175 U_NAMESPACE_END
176 
177 #endif  /* Low Level Atomic Ops Platfrom Chain */
178 
179 
180 
181 /*************************************************************************************************
182  *
183  *  UInitOnce Definitions.
184  *     These are platform neutral.
185  *
186  *************************************************************************************************/
187 
188 U_NAMESPACE_BEGIN
189 
190 struct UInitOnce {
191     u_atomic_int32_t   fState;
192     UErrorCode       fErrCode;
resetUInitOnce193     void reset() {fState = 0;};
isResetUInitOnce194     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
195 // Note: isReset() is used by service registration code.
196 //                 Thread safety of this usage needs review.
197 };
198 
199 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
200 
201 
202 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
203 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
204 
umtx_initOnce(UInitOnce & uio,T * obj,void (T::* fp)())205 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
206     if (umtx_loadAcquire(uio.fState) == 2) {
207         return;
208     }
209     if (umtx_initImplPreInit(uio)) {
210         (obj->*fp)();
211         umtx_initImplPostInit(uio);
212     }
213 }
214 
215 
216 // umtx_initOnce variant for plain functions, or static class functions.
217 //               No context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)())218 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
219     if (umtx_loadAcquire(uio.fState) == 2) {
220         return;
221     }
222     if (umtx_initImplPreInit(uio)) {
223         (*fp)();
224         umtx_initImplPostInit(uio);
225     }
226 }
227 
228 // umtx_initOnce variant for plain functions, or static class functions.
229 //               With ErrorCode, No context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)(UErrorCode &),UErrorCode & errCode)230 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
231     if (U_FAILURE(errCode)) {
232         return;
233     }
234     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
235         // We run the initialization.
236         (*fp)(errCode);
237         uio.fErrCode = errCode;
238         umtx_initImplPostInit(uio);
239     } else {
240         // Someone else already ran the initialization.
241         if (U_FAILURE(uio.fErrCode)) {
242             errCode = uio.fErrCode;
243         }
244     }
245 }
246 
247 // umtx_initOnce variant for plain functions, or static class functions,
248 //               with a context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)(T),T context)249 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
250     if (umtx_loadAcquire(uio.fState) == 2) {
251         return;
252     }
253     if (umtx_initImplPreInit(uio)) {
254         (*fp)(context);
255         umtx_initImplPostInit(uio);
256     }
257 }
258 
259 // umtx_initOnce variant for plain functions, or static class functions,
260 //               with a context parameter and an error code.
umtx_initOnce(UInitOnce & uio,void (* fp)(T,UErrorCode &),T context,UErrorCode & errCode)261 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
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)(context, 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 U_NAMESPACE_END
279 
280 
281 
282 /*************************************************************************************************
283  *
284  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
285  *         TODO:  Add a C++11 version.
286  *                Need to convert all mutex using files to C++ first.
287  *
288  *************************************************************************************************/
289 
290 #if defined(U_USER_MUTEX_H)
291 // #inlcude "U_USER_MUTEX_H"
292 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
293 
294 #elif U_PLATFORM_HAS_WIN32_API
295 
296 /* Windows Definitions.
297  *    Windows comes first in the platform chain.
298  *    Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
299  */
300 
301 
302 /* For CRITICAL_SECTION */
303 
304 /*
305  *   Note: there is an earlier include of windows.h in this file, but it is in
306  *         different conditionals.
307  *         This one is needed if we are using C++11 for atomic ops, but
308  *         win32 APIs for Critical Sections.
309  */
310 
311 # define WIN32_LEAN_AND_MEAN
312 # define VC_EXTRALEAN
313 # define NOUSER
314 # define NOSERVICE
315 # define NOIME
316 # define NOMCX
317 # ifndef NOMINMAX
318 # define NOMINMAX
319 # endif
320 # include <windows.h>
321 
322 
323 typedef struct UMutex {
324     icu::UInitOnce    fInitOnce;
325     CRITICAL_SECTION  fCS;
326 } UMutex;
327 
328 /* Initializer for a static UMUTEX. Deliberately contains no value for the
329  *  CRITICAL_SECTION.
330  */
331 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
332 
333 struct UConditionVar {
334     HANDLE           fEntryGate;
335     HANDLE           fExitGate;
336     int32_t          fWaitCount;
337 };
338 
339 #define U_CONDITION_INITIALIZER {NULL, NULL, 0}
340 
341 
342 
343 #elif U_PLATFORM_IMPLEMENTS_POSIX
344 
345 /*
346  *  POSIX platform
347  */
348 
349 #include <pthread.h>
350 
351 struct UMutex {
352     pthread_mutex_t  fMutex;
353 };
354 typedef struct UMutex UMutex;
355 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
356 
357 struct UConditionVar {
358     pthread_cond_t   fCondition;
359 };
360 #define U_CONDITION_INITIALIZER {PTHREAD_COND_INITIALIZER}
361 
362 #else
363 
364 /*
365  *  Unknow platform type.
366  *      This is an error condition. ICU requires mutexes.
367  */
368 
369 #error Unknown Platform.
370 
371 #endif
372 
373 
374 
375 /**************************************************************************************
376  *
377  *  Mutex Implementation function declaratations.
378  *     Declarations are platform neutral.
379  *     Implementations, in umutex.cpp, are platform specific.
380  *
381  ************************************************************************************/
382 
383 /* Lock a mutex.
384  * @param mutex The given mutex to be locked.  Pass NULL to specify
385  *              the global ICU mutex.  Recursive locks are an error
386  *              and may cause a deadlock on some platforms.
387  */
388 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
389 
390 /* Unlock a mutex.
391  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
392  *              the global ICU mutex.
393  */
394 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
395 
396 /*
397  * Wait on a condition variable.
398  * The calling thread will unlock the mutex and wait on the condition variable.
399  * The mutex must be locked by the calling thread when invoking this function.
400  *
401  * @param cond the condition variable to wait on.
402  * @param mutex the associated mutex.
403  */
404 
405 U_INTERNAL void U_EXPORT2 umtx_condWait(UConditionVar *cond, UMutex *mutex);
406 
407 
408 /*
409  * Broadcast wakeup of all threads waiting on a Condition.
410  * The associated mutex must be locked by the calling thread when calling
411  * this function; this is a temporary ICU restriction.
412  *
413  * @param cond the condition variable.
414  */
415 U_INTERNAL void U_EXPORT2 umtx_condBroadcast(UConditionVar *cond);
416 
417 /*
418  * Signal a condition variable, waking up one waiting thread.
419  * CAUTION: Do not use. Place holder only. Not implemented for Windows.
420  */
421 U_INTERNAL void U_EXPORT2 umtx_condSignal(UConditionVar *cond);
422 
423 #endif /* UMUTEX_H */
424 /*eof*/
425