• 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 
97 U_NAMESPACE_BEGIN
98 typedef volatile LONG u_atomic_int32_t;
99 #define ATOMIC_INT32_T_INITIALIZER(val) val
100 
101 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
102     return InterlockedCompareExchange(&var, 0, 0);
103 }
104 
105 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
106     InterlockedExchange(&var, val);
107 }
108 
109 
110 inline int32_t umtx_atomic_inc(u_atomic_int32_t *var) {
111     return InterlockedIncrement(var);
112 }
113 
114 inline int32_t umtx_atomic_dec(u_atomic_int32_t *var) {
115     return InterlockedDecrement(var);
116 }
117 U_NAMESPACE_END
118 
119 
120 #elif U_HAVE_GCC_ATOMICS
121 /*
122  * gcc atomic ops. These are available on several other compilers as well.
123  */
124 
125 U_NAMESPACE_BEGIN
126 typedef int32_t u_atomic_int32_t;
127 #define ATOMIC_INT32_T_INITIALIZER(val) val
128 
129 inline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
130     int32_t val = var;
131     __sync_synchronize();
132     return val;
133 }
134 
135 inline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
136     __sync_synchronize();
137     var = val;
138 }
139 
140 inline int32_t umtx_atomic_inc(u_atomic_int32_t *p)  {
141    return __sync_add_and_fetch(p, 1);
142 }
143 
144 inline int32_t umtx_atomic_dec(u_atomic_int32_t *p)  {
145    return __sync_sub_and_fetch(p, 1);
146 }
147 U_NAMESPACE_END
148 
149 #else
150 
151 /*
152  * Unknown Platform. Use out-of-line functions, which in turn use mutexes.
153  *                   Slow but correct.
154  */
155 
156 #define U_NO_PLATFORM_ATOMICS
157 
158 U_NAMESPACE_BEGIN
159 typedef int32_t u_atomic_int32_t;
160 #define ATOMIC_INT32_T_INITIALIZER(val) val
161 
162 U_COMMON_API int32_t U_EXPORT2
163 umtx_loadAcquire(u_atomic_int32_t &var);
164 
165 U_COMMON_API void U_EXPORT2
166 umtx_storeRelease(u_atomic_int32_t &var, int32_t val);
167 
168 U_COMMON_API int32_t U_EXPORT2
169 umtx_atomic_inc(u_atomic_int32_t *p);
170 
171 U_COMMON_API int32_t U_EXPORT2
172 umtx_atomic_dec(u_atomic_int32_t *p);
173 
174 U_NAMESPACE_END
175 
176 #endif  /* Low Level Atomic Ops Platfrom Chain */
177 
178 
179 
180 /*************************************************************************************************
181  *
182  *  UInitOnce Definitions.
183  *     These are platform neutral.
184  *
185  *************************************************************************************************/
186 
187 U_NAMESPACE_BEGIN
188 
189 struct UInitOnce {
190     u_atomic_int32_t   fState;
191     UErrorCode       fErrCode;
resetUInitOnce192     void reset() {fState = 0;};
isResetUInitOnce193     UBool isReset() {return umtx_loadAcquire(fState) == 0;};
194 // Note: isReset() is used by service registration code.
195 //                 Thread safety of this usage needs review.
196 };
197 
198 #define U_INITONCE_INITIALIZER {ATOMIC_INT32_T_INITIALIZER(0), U_ZERO_ERROR}
199 
200 
201 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &);
202 U_COMMON_API void  U_EXPORT2 umtx_initImplPostInit(UInitOnce &);
203 
umtx_initOnce(UInitOnce & uio,T * obj,void (T::* fp)())204 template<class T> void umtx_initOnce(UInitOnce &uio, T *obj, void (T::*fp)()) {
205     if (umtx_loadAcquire(uio.fState) == 2) {
206         return;
207     }
208     if (umtx_initImplPreInit(uio)) {
209         (obj->*fp)();
210         umtx_initImplPostInit(uio);
211     }
212 }
213 
214 
215 // umtx_initOnce variant for plain functions, or static class functions.
216 //               No context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)())217 inline void umtx_initOnce(UInitOnce &uio, void (*fp)()) {
218     if (umtx_loadAcquire(uio.fState) == 2) {
219         return;
220     }
221     if (umtx_initImplPreInit(uio)) {
222         (*fp)();
223         umtx_initImplPostInit(uio);
224     }
225 }
226 
227 // umtx_initOnce variant for plain functions, or static class functions.
228 //               With ErrorCode, No context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)(UErrorCode &),UErrorCode & errCode)229 inline void umtx_initOnce(UInitOnce &uio, void (*fp)(UErrorCode &), UErrorCode &errCode) {
230     if (U_FAILURE(errCode)) {
231         return;
232     }
233     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
234         // We run the initialization.
235         (*fp)(errCode);
236         uio.fErrCode = errCode;
237         umtx_initImplPostInit(uio);
238     } else {
239         // Someone else already ran the initialization.
240         if (U_FAILURE(uio.fErrCode)) {
241             errCode = uio.fErrCode;
242         }
243     }
244 }
245 
246 // umtx_initOnce variant for plain functions, or static class functions,
247 //               with a context parameter.
umtx_initOnce(UInitOnce & uio,void (* fp)(T),T context)248 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T), T context) {
249     if (umtx_loadAcquire(uio.fState) == 2) {
250         return;
251     }
252     if (umtx_initImplPreInit(uio)) {
253         (*fp)(context);
254         umtx_initImplPostInit(uio);
255     }
256 }
257 
258 // umtx_initOnce variant for plain functions, or static class functions,
259 //               with a context parameter and an error code.
umtx_initOnce(UInitOnce & uio,void (* fp)(T,UErrorCode &),T context,UErrorCode & errCode)260 template<class T> void umtx_initOnce(UInitOnce &uio, void (*fp)(T, UErrorCode &), T context, UErrorCode &errCode) {
261     if (U_FAILURE(errCode)) {
262         return;
263     }
264     if (umtx_loadAcquire(uio.fState) != 2 && umtx_initImplPreInit(uio)) {
265         // We run the initialization.
266         (*fp)(context, errCode);
267         uio.fErrCode = errCode;
268         umtx_initImplPostInit(uio);
269     } else {
270         // Someone else already ran the initialization.
271         if (U_FAILURE(uio.fErrCode)) {
272             errCode = uio.fErrCode;
273         }
274     }
275 }
276 
277 U_NAMESPACE_END
278 
279 
280 
281 /*************************************************************************************************
282  *
283  *  Mutex Definitions. Platform Dependent, #if platform chain follows.
284  *         TODO:  Add a C++11 version.
285  *                Need to convert all mutex using files to C++ first.
286  *
287  *************************************************************************************************/
288 
289 #if defined(U_USER_MUTEX_H)
290 // #inlcude "U_USER_MUTEX_H"
291 #include U_MUTEX_XSTR(U_USER_MUTEX_H)
292 
293 #elif U_PLATFORM_HAS_WIN32_API
294 
295 /* Windows Definitions.
296  *    Windows comes first in the platform chain.
297  *    Cygwin (and possibly others) have both WIN32 and POSIX APIs. Prefer Win32 in this case.
298  */
299 
300 
301 /* For CRITICAL_SECTION */
302 
303 /*
304  *   Note: there is an earlier include of windows.h in this file, but it is in
305  *         different conditionals.
306  *         This one is needed if we are using C++11 for atomic ops, but
307  *         win32 APIs for Critical Sections.
308  */
309 
310 # define WIN32_LEAN_AND_MEAN
311 # define VC_EXTRALEAN
312 # define NOUSER
313 # define NOSERVICE
314 # define NOIME
315 # define NOMCX
316 # ifndef NOMINMAX
317 # define NOMINMAX
318 # endif
319 # include <windows.h>
320 
321 
322 typedef struct UMutex {
323     icu::UInitOnce         fInitOnce;
324     CRITICAL_SECTION  fCS;
325 } UMutex;
326 
327 /* Initializer for a static UMUTEX. Deliberately contains no value for the
328  *  CRITICAL_SECTION.
329  */
330 #define U_MUTEX_INITIALIZER {U_INITONCE_INITIALIZER}
331 
332 
333 
334 #elif U_PLATFORM_IMPLEMENTS_POSIX
335 
336 /*
337  *  POSIX platform
338  */
339 
340 #include <pthread.h>
341 
342 struct UMutex {
343     pthread_mutex_t  fMutex;
344 };
345 typedef struct UMutex UMutex;
346 #define U_MUTEX_INITIALIZER  {PTHREAD_MUTEX_INITIALIZER}
347 
348 #else
349 
350 /*
351  *  Unknow platform type.
352  *      This is an error condition. ICU requires mutexes.
353  */
354 
355 #error Unknown Platform.
356 
357 #endif
358 
359 
360 
361 /**************************************************************************************
362  *
363  *  Mutex Implementation function declaratations.
364  *     Declarations are platform neutral.
365  *     Implementations, in umutex.cpp, are platform specific.
366  *
367  ************************************************************************************/
368 
369 /* Lock a mutex.
370  * @param mutex The given mutex to be locked.  Pass NULL to specify
371  *              the global ICU mutex.  Recursive locks are an error
372  *              and may cause a deadlock on some platforms.
373  */
374 U_INTERNAL void U_EXPORT2 umtx_lock(UMutex* mutex);
375 
376 /* Unlock a mutex.
377  * @param mutex The given mutex to be unlocked.  Pass NULL to specify
378  *              the global ICU mutex.
379  */
380 U_INTERNAL void U_EXPORT2 umtx_unlock (UMutex* mutex);
381 
382 #endif /* UMUTEX_H */
383 /*eof*/
384