]>
Commit | Line | Data |
---|---|---|
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; | |
193 | void reset() {fState = 0;}; | |
194 | 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 | ||
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. | |
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. | |
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. | |
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. | |
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*/ |