summaryrefslogtreecommitdiff
path: root/Build/source/libs/icu/icu-src/source/common/umutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/icu/icu-src/source/common/umutex.cpp')
-rw-r--r--Build/source/libs/icu/icu-src/source/common/umutex.cpp344
1 files changed, 85 insertions, 259 deletions
diff --git a/Build/source/libs/icu/icu-src/source/common/umutex.cpp b/Build/source/libs/icu/icu-src/source/common/umutex.cpp
index 29dbc90ec98..ccbee9960a3 100644
--- a/Build/source/libs/icu/icu-src/source/common/umutex.cpp
+++ b/Build/source/libs/icu/icu-src/source/common/umutex.cpp
@@ -24,256 +24,142 @@
#include "unicode/utypes.h"
#include "uassert.h"
+#include "ucln_cmn.h"
#include "cmemory.h"
+U_NAMESPACE_BEGIN
-// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
-static UMutex globalMutex = U_MUTEX_INITIALIZER;
-
-/*
- * ICU Mutex wrappers. Wrap operating system mutexes, giving the rest of ICU a
- * platform independent set of mutex operations. For internal ICU use only.
- */
#if defined(U_USER_MUTEX_CPP)
-// Build time user mutex hook: #include "U_USER_MUTEX_CPP"
-#include U_MUTEX_XSTR(U_USER_MUTEX_CPP)
-
-#elif U_PLATFORM_USES_ONLY_WIN32_API
-
-#if defined U_NO_PLATFORM_ATOMICS
-#error ICU on Win32 requires support for low level atomic operations.
-// Visual Studio, gcc, clang are OK. Shouldn't get here.
+// Support for including an alternate implementation of mutexes has been withdrawn.
+// See issue ICU-20185.
+#error U_USER_MUTEX_CPP not supported
#endif
-// This function is called when a test of a UInitOnce::fState reveals that
-// initialization has not completed, that we either need to call the
-// function on this thread, or wait for some other thread to complete.
-//
-// The actual call to the init function is made inline by template code
-// that knows the C++ types involved. This function returns TRUE if
-// the caller needs to call the Init function.
-//
+/*************************************************************************************************
+ *
+ * ICU Mutex wrappers.
+ *
+ *************************************************************************************************/
-U_NAMESPACE_BEGIN
+namespace {
+std::mutex *initMutex;
+std::condition_variable *initCondition;
-U_COMMON_API UBool U_EXPORT2 umtx_initImplPreInit(UInitOnce &uio) {
- for (;;) {
- int32_t previousState = InterlockedCompareExchange(
- (LONG volatile *) // this is the type given in the API doc for this function.
- &uio.fState, // Destination
- 1, // Exchange Value
- 0); // Compare value
-
- if (previousState == 0) {
- return true; // Caller will next call the init function.
- // Current state == 1.
- } else if (previousState == 2) {
- // Another thread already completed the initialization.
- // We can simply return FALSE, indicating no
- // further action is needed by the caller.
- return FALSE;
- } else {
- // Another thread is currently running the initialization.
- // Wait until it completes.
- do {
- Sleep(1);
- previousState = umtx_loadAcquire(uio.fState);
- } while (previousState == 1);
- }
- }
-}
+// The ICU global mutex.
+// Used when ICU implementation code passes nullptr for the mutex pointer.
+UMutex globalMutex;
-// This function is called by the thread that ran an initialization function,
-// just after completing the function.
+std::once_flag initFlag;
+std::once_flag *pInitFlag = &initFlag;
-U_COMMON_API void U_EXPORT2 umtx_initImplPostInit(UInitOnce &uio) {
- umtx_storeRelease(uio.fState, 2);
-}
+} // Anonymous namespace
-U_NAMESPACE_END
+U_CDECL_BEGIN
+static UBool U_CALLCONV umtx_cleanup() {
+ initMutex->~mutex();
+ initCondition->~condition_variable();
+ UMutex::cleanup();
-static void winMutexInit(CRITICAL_SECTION *cs) {
- InitializeCriticalSection(cs);
- return;
+ // Reset the once_flag, by destructing it and creating a fresh one in its place.
+ // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
+ pInitFlag->~once_flag();
+ pInitFlag = new(&initFlag) std::once_flag();
+ return true;
}
-U_CAPI void U_EXPORT2
-umtx_lock(UMutex *mutex) {
- if (mutex == NULL) {
- mutex = &globalMutex;
- }
- CRITICAL_SECTION *cs = &mutex->fCS;
- umtx_initOnce(mutex->fInitOnce, winMutexInit, cs);
- EnterCriticalSection(cs);
-}
-
-U_CAPI void U_EXPORT2
-umtx_unlock(UMutex* mutex)
-{
- if (mutex == NULL) {
- mutex = &globalMutex;
- }
- LeaveCriticalSection(&mutex->fCS);
+static void U_CALLCONV umtx_init() {
+ initMutex = STATIC_NEW(std::mutex);
+ initCondition = STATIC_NEW(std::condition_variable);
+ ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
}
+U_CDECL_END
-U_CAPI void U_EXPORT2
-umtx_condBroadcast(UConditionVar *condition) {
- // We require that the associated mutex be held by the caller,
- // so access to fWaitCount is protected and safe. No other thread can
- // call condWait() while we are here.
- if (condition->fWaitCount == 0) {
- return;
+std::mutex *UMutex::getMutex() {
+ std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
+ if (retPtr == nullptr) {
+ std::call_once(*pInitFlag, umtx_init);
+ std::lock_guard<std::mutex> guard(*initMutex);
+ retPtr = fMutex.load(std::memory_order_acquire);
+ if (retPtr == nullptr) {
+ fMutex = new(fStorage) std::mutex();
+ retPtr = fMutex;
+ fListLink = gListHead;
+ gListHead = this;
+ }
}
- ResetEvent(condition->fExitGate);
- SetEvent(condition->fEntryGate);
+ U_ASSERT(retPtr != nullptr);
+ return retPtr;
}
-U_CAPI void U_EXPORT2
-umtx_condSignal(UConditionVar * /* condition */) {
- // Function not implemented. There is no immediate requirement from ICU to have it.
- // Once ICU drops support for Windows XP and Server 2003, ICU Condition Variables will be
- // changed to be thin wrappers on native Windows CONDITION_VARIABLEs, and this function
- // becomes trivial to provide.
- U_ASSERT(FALSE);
-}
+UMutex *UMutex::gListHead = nullptr;
-U_CAPI void U_EXPORT2
-umtx_condWait(UConditionVar *condition, UMutex *mutex) {
- if (condition->fEntryGate == NULL) {
- // Note: because the associated mutex must be locked when calling
- // wait, we know that there can not be multiple threads
- // running here with the same condition variable.
- // Meaning that lazy initialization is safe.
- U_ASSERT(condition->fExitGate == NULL);
- condition->fEntryGate = CreateEvent(NULL, // Security Attributes
- TRUE, // Manual Reset
- FALSE, // Initially reset
- NULL); // Name.
- U_ASSERT(condition->fEntryGate != NULL);
- condition->fExitGate = CreateEvent(NULL, TRUE, TRUE, NULL);
- U_ASSERT(condition->fExitGate != NULL);
- }
-
- condition->fWaitCount++;
- umtx_unlock(mutex);
- WaitForSingleObject(condition->fEntryGate, INFINITE);
- umtx_lock(mutex);
- condition->fWaitCount--;
- if (condition->fWaitCount == 0) {
- // All threads that were waiting at the entry gate have woken up
- // and moved through. Shut the entry gate and open the exit gate.
- ResetEvent(condition->fEntryGate);
- SetEvent(condition->fExitGate);
- } else {
- umtx_unlock(mutex);
- WaitForSingleObject(condition->fExitGate, INFINITE);
- umtx_lock(mutex);
+void UMutex::cleanup() {
+ UMutex *next = nullptr;
+ for (UMutex *m = gListHead; m != nullptr; m = next) {
+ (*m->fMutex).~mutex();
+ m->fMutex = nullptr;
+ next = m->fListLink;
+ m->fListLink = nullptr;
}
+ gListHead = nullptr;
}
-#elif U_PLATFORM_IMPLEMENTS_POSIX
-
-//-------------------------------------------------------------------------------------------
-//
-// POSIX specific definitions
-//
-//-------------------------------------------------------------------------------------------
-
-# include <pthread.h>
-
-// Each UMutex consists of a pthread_mutex_t.
-// All are statically initialized and ready for use.
-// There is no runtime mutex initialization code needed.
-
U_CAPI void U_EXPORT2
umtx_lock(UMutex *mutex) {
- if (mutex == NULL) {
+ if (mutex == nullptr) {
mutex = &globalMutex;
}
- int sysErr = pthread_mutex_lock(&mutex->fMutex);
- (void)sysErr; // Suppress unused variable warnings.
- U_ASSERT(sysErr == 0);
+ mutex->lock();
}
U_CAPI void U_EXPORT2
umtx_unlock(UMutex* mutex)
{
- if (mutex == NULL) {
- mutex = &globalMutex;
- }
- int sysErr = pthread_mutex_unlock(&mutex->fMutex);
- (void)sysErr; // Suppress unused variable warnings.
- U_ASSERT(sysErr == 0);
-}
-
-
-U_CAPI void U_EXPORT2
-umtx_condWait(UConditionVar *cond, UMutex *mutex) {
- if (mutex == NULL) {
+ if (mutex == nullptr) {
mutex = &globalMutex;
}
- int sysErr = pthread_cond_wait(&cond->fCondition, &mutex->fMutex);
- (void)sysErr;
- U_ASSERT(sysErr == 0);
+ mutex->unlock();
}
-U_CAPI void U_EXPORT2
-umtx_condBroadcast(UConditionVar *cond) {
- int sysErr = pthread_cond_broadcast(&cond->fCondition);
- (void)sysErr;
- U_ASSERT(sysErr == 0);
-}
-
-U_CAPI void U_EXPORT2
-umtx_condSignal(UConditionVar *cond) {
- int sysErr = pthread_cond_signal(&cond->fCondition);
- (void)sysErr;
- U_ASSERT(sysErr == 0);
-}
-
-
-
-U_NAMESPACE_BEGIN
-
-static pthread_mutex_t initMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t initCondition = PTHREAD_COND_INITIALIZER;
+/*************************************************************************************************
+ *
+ * UInitOnce Implementation
+ *
+ *************************************************************************************************/
// This function is called when a test of a UInitOnce::fState reveals that
-// initialization has not completed, that we either need to call the
+// initialization has not completed, that we either need to call the init
// function on this thread, or wait for some other thread to complete.
//
// The actual call to the init function is made inline by template code
-// that knows the C++ types involved. This function returns TRUE if
+// that knows the C++ types involved. This function returns true if
// the caller needs to call the Init function.
//
U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce &uio) {
- pthread_mutex_lock(&initMutex);
- int32_t state = uio.fState;
- if (state == 0) {
+ std::call_once(*pInitFlag, umtx_init);
+ std::unique_lock<std::mutex> lock(*initMutex);
+ if (umtx_loadAcquire(uio.fState) == 0) {
umtx_storeRelease(uio.fState, 1);
- pthread_mutex_unlock(&initMutex);
- return TRUE; // Caller will next call the init function.
+ return true; // Caller will next call the init function.
} else {
- while (uio.fState == 1) {
+ while (umtx_loadAcquire(uio.fState) == 1) {
// Another thread is currently running the initialization.
// Wait until it completes.
- pthread_cond_wait(&initCondition, &initMutex);
+ initCondition->wait(lock);
}
- pthread_mutex_unlock(&initMutex);
U_ASSERT(uio.fState == 2);
- return FALSE;
+ return false;
}
}
-
// This function is called by the thread that ran an initialization function,
// just after completing the function.
// Some threads may be waiting on the condition, requiring the broadcast wakeup.
@@ -282,80 +168,20 @@ umtx_initImplPreInit(UInitOnce &uio) {
U_COMMON_API void U_EXPORT2
umtx_initImplPostInit(UInitOnce &uio) {
- pthread_mutex_lock(&initMutex);
- umtx_storeRelease(uio.fState, 2);
- pthread_cond_broadcast(&initCondition);
- pthread_mutex_unlock(&initMutex);
-}
-
-U_NAMESPACE_END
-
-// End of POSIX specific umutex implementation.
-
-#else // Platform #define chain.
-
-#error Unknown Platform
-
-#endif // Platform #define chain.
-
-
-//-------------------------------------------------------------------------------
-//
-// Atomic Operations, out-of-line versions.
-// These are conditional, only defined if better versions
-// were not available for the platform.
-//
-// These versions are platform neutral.
-//
-//--------------------------------------------------------------------------------
-
-#if defined U_NO_PLATFORM_ATOMICS
-static UMutex gIncDecMutex = U_MUTEX_INITIALIZER;
-
-U_NAMESPACE_BEGIN
-
-U_COMMON_API int32_t U_EXPORT2
-umtx_atomic_inc(u_atomic_int32_t *p) {
- int32_t retVal;
- umtx_lock(&gIncDecMutex);
- retVal = ++(*p);
- umtx_unlock(&gIncDecMutex);
- return retVal;
-}
-
-
-U_COMMON_API int32_t U_EXPORT2
-umtx_atomic_dec(u_atomic_int32_t *p) {
- int32_t retVal;
- umtx_lock(&gIncDecMutex);
- retVal = --(*p);
- umtx_unlock(&gIncDecMutex);
- return retVal;
-}
-
-U_COMMON_API int32_t U_EXPORT2
-umtx_loadAcquire(u_atomic_int32_t &var) {
- umtx_lock(&gIncDecMutex);
- int32_t val = var;
- umtx_unlock(&gIncDecMutex);
- return val;
-}
-
-U_COMMON_API void U_EXPORT2
-umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
- umtx_lock(&gIncDecMutex);
- var = val;
- umtx_unlock(&gIncDecMutex);
+ {
+ std::unique_lock<std::mutex> lock(*initMutex);
+ umtx_storeRelease(uio.fState, 2);
+ }
+ initCondition->notify_all();
}
U_NAMESPACE_END
-#endif
-//--------------------------------------------------------------------------
-//
-// Deprecated functions for setting user mutexes.
-//
-//--------------------------------------------------------------------------
+/*************************************************************************************************
+ *
+ * Deprecated functions for setting user mutexes.
+ *
+ *************************************************************************************************/
U_DEPRECATED void U_EXPORT2
u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,