• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ******************************************************************************
3 *
4 *   Copyright (C) 1997-2013, International Business Machines
5 *   Corporation and others.  All Rights Reserved.
6 *
7 ******************************************************************************
8 *
9 * File umutex.cpp
10 *
11 * Modification History:
12 *
13 *   Date        Name        Description
14 *   04/02/97    aliu        Creation.
15 *   04/07/99    srl         updated
16 *   05/13/99    stephen     Changed to umutex (from cmutex).
17 *   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
18 ******************************************************************************
19 */
20 
21 #include "umutex.h"
22 
23 #include "unicode/utypes.h"
24 #include "uassert.h"
25 #include "cmemory.h"
26 #include "ucln_cmn.h"
27 
28 
29 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
30 static UMutex   globalMutex = U_MUTEX_INITIALIZER;
31 
32 /*
33  * ICU Mutex wrappers.  Wrap operating system mutexes, giving the rest of ICU a
34  * platform independent set of mutex operations.  For internal ICU use only.
35  */
36 
37 #if defined(U_USER_MUTEX_CPP)
38 // Build time user mutex hook: #include "U_USER_MUTEX_CPP"
39 #include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
40 
41 #elif U_PLATFORM_HAS_WIN32_API
42 
43 //-------------------------------------------------------------------------------------------
44 //
45 //    Windows Specific Definitions
46 //
47 //        Note: Cygwin (and possibly others) have both WIN32 and POSIX.
48 //              Prefer Win32 in these cases.  (Win32 comes ahead in the #if chain)
49 //
50 //-------------------------------------------------------------------------------------------
51 
52 #if defined U_NO_PLATFORM_ATOMICS
53 #error ICU on Win32 requires support for low level atomic operations.
54 // Visual Studio, gcc, clang are OK. Shouldn't get here.
55 #endif
56 
57 
58 // This function is called when a test of a UInitOnce::fState reveals that
59 //   initialization has not completed, that we either need to call the
60 //   function on this thread, or wait for some other thread to complete.
61 //
62 // The actual call to the init function is made inline by template code
63 //   that knows the C++ types involved. This function returns TRUE if
64 //   the caller needs to call the Init function.
65 //
66 
67 U_NAMESPACE_BEGIN
68 
umtx_initImplPreInit(UInitOnce & uio)69 U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
70     for (;;) {
71         int32_t previousState = InterlockedCompareExchange(
72 #if (U_PLATFORM == U_PF_MINGW) || (U_PLATFORM == U_PF_CYGWIN)
73            (LONG volatile *) // this is the type given in the API doc for this function.
74 #endif
75             &uio.fState,  //  Destination
76             1,            //  Exchange Value
77             0);           //  Compare value
78 
79         if (previousState == 0) {
80             return true;   // Caller will next call the init function.
81                            // Current state == 1.
82         } else if (previousState == 2) {
83             // Another thread already completed the initialization.
84             //   We can simply return FALSE, indicating no
85             //   further action is needed by the caller.
86             return FALSE;
87         } else {
88             // Another thread is currently running the initialization.
89             // Wait until it completes.
90             do {
91                 Sleep(1);
92                 previousState = umtx_loadAcquire(uio.fState);
93             } while (previousState == 1);
94         }
95     }
96 }
97 
98 // This function is called by the thread that ran an initialization function,
99 // just after completing the function.
100 //
101 //   success: True:  the inialization succeeded. No further calls to the init
102 //                   function will be made.
103 //            False: the initializtion failed. The next call to umtx_initOnce()
104 //                   will retry the initialization.
105 
umtx_initImplPostInit(UInitOnce & uio)106 U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
107     umtx_storeRelease(uio.fState, 2);
108 }
109 
110 U_NAMESPACE_END
111 
winMutexInit(CRITICAL_SECTION * cs)112 static void winMutexInit(CRITICAL_SECTION *cs) {
113     InitializeCriticalSection(cs);
114     return;
115 }
116 
117 U_CAPI void  U_EXPORT2
umtx_lock(UMutex * mutex)118 umtx_lock(UMutex *mutex) {
119     if (mutex == NULL) {
120         mutex = &globalMutex;
121     }
122     CRITICAL_SECTION *cs = &mutex->fCS;
123     umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
124     EnterCriticalSection(cs);
125 }
126 
127 U_CAPI void  U_EXPORT2
umtx_unlock(UMutex * mutex)128 umtx_unlock(UMutex* mutex)
129 {
130     if (mutex == NULL) {
131         mutex = &globalMutex;
132     }
133     LeaveCriticalSection(&mutex->fCS);
134 }
135 
136 #elif U_PLATFORM_IMPLEMENTS_POSIX
137 
138 //-------------------------------------------------------------------------------------------
139 //
140 //  POSIX specific definitions
141 //
142 //-------------------------------------------------------------------------------------------
143 
144 # include <pthread.h>
145 
146 // Each UMutex consists of a pthread_mutex_t.
147 // All are statically initialized and ready for use.
148 // There is no runtime mutex initialization code needed.
149 
150 U_CAPI void  U_EXPORT2
umtx_lock(UMutex * mutex)151 umtx_lock(UMutex *mutex) {
152     if (mutex == NULL) {
153         mutex = &globalMutex;
154     }
155     int sysErr = pthread_mutex_lock(&mutex->fMutex);
156     (void)sysErr;   // Suppress unused variable warnings.
157     U_ASSERT(sysErr == 0);
158 }
159 
160 
161 U_CAPI void  U_EXPORT2
umtx_unlock(UMutex * mutex)162 umtx_unlock(UMutex* mutex)
163 {
164     if (mutex == NULL) {
165         mutex = &globalMutex;
166     }
167     int sysErr = pthread_mutex_unlock(&mutex->fMutex);
168     (void)sysErr;   // Suppress unused variable warnings.
169     U_ASSERT(sysErr == 0);
170 }
171 
172 U_NAMESPACE_BEGIN
173 
174 static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
175 static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
176 
177 
178 // This function is called when a test of a UInitOnce::fState reveals that
179 //   initialization has not completed, that we either need to call the
180 //   function on this thread, or wait for some other thread to complete.
181 //
182 // The actual call to the init function is made inline by template code
183 //   that knows the C++ types involved. This function returns TRUE if
184 //   the caller needs to call the Init function.
185 //
186 U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce & uio)187 umtx_initImplPreInit(UInitOnce &uio) {
188     pthread_mutex_lock(&initMutex);
189     int32_t state = uio.fState;
190     if (state == 0) {
191         umtx_storeRelease(uio.fState, 1);
192         pthread_mutex_unlock(&initMutex);
193         return TRUE;   // Caller will next call the init function.
194     } else {
195         while (uio.fState == 1) {
196             // Another thread is currently running the initialization.
197             // Wait until it completes.
198             pthread_cond_wait(&initCondition, &initMutex);
199         }
200         pthread_mutex_unlock(&initMutex);
201         U_ASSERT(uio.fState == 2);
202         return FALSE;
203     }
204 }
205 
206 
207 
208 // This function is called by the thread that ran an initialization function,
209 // just after completing the function.
210 //   Some threads may be waiting on the condition, requiring the broadcast wakeup.
211 //   Some threads may be racing to test the fState variable outside of the mutex,
212 //   requiring the use of store/release when changing its value.
213 
214 U_COMMON_API void U_EXPORT2
umtx_initImplPostInit(UInitOnce & uio)215 umtx_initImplPostInit(UInitOnce &uio) {
216     pthread_mutex_lock(&initMutex);
217     umtx_storeRelease(uio.fState, 2);
218     pthread_cond_broadcast(&initCondition);
219     pthread_mutex_unlock(&initMutex);
220 }
221 
222 U_NAMESPACE_END
223 
224 // End of POSIX specific umutex implementation.
225 
226 #else  // Platform #define chain.
227 
228 #error Unknown Platform
229 
230 #endif  // Platform #define chain.
231 
232 
233 //-------------------------------------------------------------------------------
234 //
235 //   Atomic Operations, out-of-line versions.
236 //                      These are conditional, only defined if better versions
237 //                      were not available for the platform.
238 //
239 //                      These versions are platform neutral.
240 //
241 //--------------------------------------------------------------------------------
242 
243 #if defined U_NO_PLATFORM_ATOMICS
244 static UMutex   gIncDecMutex = U_MUTEX_INITIALIZER;
245 
246 U_NAMESPACE_BEGIN
247 
248 U_COMMON_API int32_t U_EXPORT2
umtx_atomic_inc(u_atomic_int32_t * p)249 umtx_atomic_inc(u_atomic_int32_t *p)  {
250     int32_t retVal;
251     umtx_lock(&gIncDecMutex);
252     retVal = ++(*p);
253     umtx_unlock(&gIncDecMutex);
254     return retVal;
255 }
256 
257 
258 U_COMMON_API int32_t U_EXPORT2
umtx_atomic_dec(u_atomic_int32_t * p)259 umtx_atomic_dec(u_atomic_int32_t *p) {
260     int32_t retVal;
261     umtx_lock(&gIncDecMutex);
262     retVal = --(*p);
263     umtx_unlock(&gIncDecMutex);
264     return retVal;
265 }
266 
267 U_COMMON_API int32_t U_EXPORT2
umtx_loadAcquire(u_atomic_int32_t & var)268 umtx_loadAcquire(u_atomic_int32_t &var) {
269     int32_t val = var;
270     umtx_lock(&gIncDecMutex);
271     umtx_unlock(&gIncDecMutex);
272     return val;
273 }
274 
275 U_COMMON_API void U_EXPORT2
umtx_storeRelease(u_atomic_int32_t & var,int32_t val)276 umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
277     umtx_lock(&gIncDecMutex);
278     umtx_unlock(&gIncDecMutex);
279     var = val;
280 }
281 
282 U_NAMESPACE_END
283 #endif
284 
285 //--------------------------------------------------------------------------
286 //
287 //  Deprecated functions for setting user mutexes.
288 //
289 //--------------------------------------------------------------------------
290 
291 U_DEPRECATED void U_EXPORT2
u_setMutexFunctions(const void *,UMtxInitFn *,UMtxFn *,UMtxFn *,UMtxFn *,UErrorCode * status)292 u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
293                     UMtxFn *,  UMtxFn *, UErrorCode *status) {
294     if (U_SUCCESS(*status)) {
295         *status = U_UNSUPPORTED_ERROR;
296     }
297     return;
298 }
299 
300 
301 
302 U_DEPRECATED void U_EXPORT2
u_setAtomicIncDecFunctions(const void *,UMtxAtomicFn *,UMtxAtomicFn *,UErrorCode * status)303 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
304                            UErrorCode *status) {
305     if (U_SUCCESS(*status)) {
306         *status = U_UNSUPPORTED_ERROR;
307     }
308     return;
309 }
310