intl/icu/source/common/umutex.cpp

Wed, 31 Dec 2014 07:22:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:22:50 +0100
branch
TOR_BUG_3246
changeset 4
fc2d59ddac77
permissions
-rw-r--r--

Correct previous dual key logic pending first delivery installment.

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

mercurial