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