summaryrefslogtreecommitdiffstats
path: root/intl/icu/source/common/umutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--intl/icu/source/common/umutex.cpp224
1 files changed, 224 insertions, 0 deletions
diff --git a/intl/icu/source/common/umutex.cpp b/intl/icu/source/common/umutex.cpp
new file mode 100644
index 0000000000..6c3452ca1b
--- /dev/null
+++ b/intl/icu/source/common/umutex.cpp
@@ -0,0 +1,224 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
+/*
+******************************************************************************
+*
+* Copyright (C) 1997-2016, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+******************************************************************************
+*
+* File umutex.cpp
+*
+* Modification History:
+*
+* Date Name Description
+* 04/02/97 aliu Creation.
+* 04/07/99 srl updated
+* 05/13/99 stephen Changed to umutex (from cmutex).
+* 11/22/99 aliu Make non-global mutex autoinitialize [j151]
+******************************************************************************
+*/
+
+#include "umutex.h"
+
+#include "unicode/utypes.h"
+#include "uassert.h"
+#include "ucln_cmn.h"
+#include "cmemory.h"
+
+U_NAMESPACE_BEGIN
+
+
+#if defined(U_USER_MUTEX_CPP)
+// Support for including an alternate implementation of mutexes has been withdrawn.
+// See issue ICU-20185.
+#error U_USER_MUTEX_CPP not supported
+#endif
+
+
+/*************************************************************************************************
+ *
+ * ICU Mutex wrappers.
+ *
+ *************************************************************************************************/
+
+#ifndef __wasi__
+namespace {
+std::mutex *initMutex;
+std::condition_variable *initCondition;
+
+// The ICU global mutex.
+// Used when ICU implementation code passes nullptr for the mutex pointer.
+UMutex globalMutex;
+
+std::once_flag initFlag;
+std::once_flag *pInitFlag = &initFlag;
+
+} // Anonymous namespace
+#endif
+
+U_CDECL_BEGIN
+static UBool U_CALLCONV umtx_cleanup() {
+#ifndef __wasi__
+ initMutex->~mutex();
+ initCondition->~condition_variable();
+ UMutex::cleanup();
+
+ // 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();
+#endif
+ return true;
+}
+
+static void U_CALLCONV umtx_init() {
+#ifndef __wasi__
+ initMutex = STATIC_NEW(std::mutex);
+ initCondition = STATIC_NEW(std::condition_variable);
+ ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
+#endif
+}
+U_CDECL_END
+
+
+#ifndef __wasi__
+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;
+ }
+ }
+ U_ASSERT(retPtr != nullptr);
+ return retPtr;
+}
+#endif
+
+UMutex *UMutex::gListHead = nullptr;
+
+void UMutex::cleanup() {
+ UMutex *next = nullptr;
+ for (UMutex *m = gListHead; m != nullptr; m = next) {
+#ifndef __wasi__
+ (*m->fMutex).~mutex();
+ m->fMutex = nullptr;
+#endif
+ next = m->fListLink;
+ m->fListLink = nullptr;
+ }
+ gListHead = nullptr;
+}
+
+
+U_CAPI void U_EXPORT2
+umtx_lock(UMutex *mutex) {
+#ifndef __wasi__
+ if (mutex == nullptr) {
+ mutex = &globalMutex;
+ }
+ mutex->lock();
+#endif
+}
+
+
+U_CAPI void U_EXPORT2
+umtx_unlock(UMutex* mutex)
+{
+#ifndef __wasi__
+ if (mutex == nullptr) {
+ mutex = &globalMutex;
+ }
+ mutex->unlock();
+#endif
+}
+
+
+/*************************************************************************************************
+ *
+ * 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 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
+// the caller needs to call the Init function.
+//
+U_COMMON_API UBool U_EXPORT2
+umtx_initImplPreInit(UInitOnce &uio) {
+#ifndef __wasi__
+ std::call_once(*pInitFlag, umtx_init);
+ std::unique_lock<std::mutex> lock(*initMutex);
+#endif
+ if (umtx_loadAcquire(uio.fState) == 0) {
+ umtx_storeRelease(uio.fState, 1);
+ return true; // Caller will next call the init function.
+ } else {
+#ifndef __wasi__
+ while (umtx_loadAcquire(uio.fState) == 1) {
+ // Another thread is currently running the initialization.
+ // Wait until it completes.
+ initCondition->wait(lock);
+ }
+ U_ASSERT(uio.fState == 2);
+#endif
+ 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.
+// Some threads may be racing to test the fState variable outside of the mutex,
+// requiring the use of store/release when changing its value.
+
+U_COMMON_API void U_EXPORT2
+umtx_initImplPostInit(UInitOnce &uio) {
+#ifndef __wasi__
+ {
+ std::unique_lock<std::mutex> lock(*initMutex);
+ umtx_storeRelease(uio.fState, 2);
+ }
+ initCondition->notify_all();
+#endif
+}
+
+U_NAMESPACE_END
+
+/*************************************************************************************************
+ *
+ * Deprecated functions for setting user mutexes.
+ *
+ *************************************************************************************************/
+
+U_DEPRECATED void U_EXPORT2
+u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
+ UMtxFn *, UMtxFn *, UErrorCode *status) {
+ if (U_SUCCESS(*status)) {
+ *status = U_UNSUPPORTED_ERROR;
+ }
+ return;
+}
+
+
+
+U_DEPRECATED void U_EXPORT2
+u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
+ UErrorCode *status) {
+ if (U_SUCCESS(*status)) {
+ *status = U_UNSUPPORTED_ERROR;
+ }
+ return;
+}