summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/common/umutex.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'deps/icu-small/source/common/umutex.cpp')
-rw-r--r--deps/icu-small/source/common/umutex.cpp122
1 files changed, 73 insertions, 49 deletions
diff --git a/deps/icu-small/source/common/umutex.cpp b/deps/icu-small/source/common/umutex.cpp
index 20b03d6cd3..ccbee9960a 100644
--- a/deps/icu-small/source/common/umutex.cpp
+++ b/deps/icu-small/source/common/umutex.cpp
@@ -24,6 +24,7 @@
#include "unicode/utypes.h"
#include "uassert.h"
+#include "ucln_cmn.h"
#include "cmemory.h"
U_NAMESPACE_BEGIN
@@ -35,60 +36,94 @@ U_NAMESPACE_BEGIN
#error U_USER_MUTEX_CPP not supported
#endif
+
/*************************************************************************************************
*
* ICU Mutex wrappers.
*
*************************************************************************************************/
-// The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
-static UMutex *globalMutex() {
- static UMutex m = U_MUTEX_INITIALIZER;
- return &m;
-}
+namespace {
+std::mutex *initMutex;
+std::condition_variable *initCondition;
-U_CAPI void U_EXPORT2
-umtx_lock(UMutex *mutex) {
- if (mutex == nullptr) {
- mutex = globalMutex();
- }
- mutex->fMutex.lock();
-}
+// 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;
-U_CAPI void U_EXPORT2
-umtx_unlock(UMutex* mutex)
-{
- if (mutex == nullptr) {
- mutex = globalMutex();
- }
- mutex->fMutex.unlock();
-}
+} // Anonymous namespace
-UConditionVar::UConditionVar() : fCV() {
+U_CDECL_BEGIN
+static UBool U_CALLCONV umtx_cleanup() {
+ 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();
+ return true;
}
-UConditionVar::~UConditionVar() {
+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
+
+
+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;
}
-U_CAPI void U_EXPORT2
-umtx_condWait(UConditionVar *cond, UMutex *mutex) {
- if (mutex == nullptr) {
- mutex = globalMutex();
+UMutex *UMutex::gListHead = nullptr;
+
+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;
}
- cond->fCV.wait(mutex->fMutex);
+ gListHead = nullptr;
}
-U_CAPI void U_EXPORT2
-umtx_condBroadcast(UConditionVar *cond) {
- cond->fCV.notify_all();
+U_CAPI void U_EXPORT2
+umtx_lock(UMutex *mutex) {
+ if (mutex == nullptr) {
+ mutex = &globalMutex;
+ }
+ mutex->lock();
}
-U_CAPI void U_EXPORT2
-umtx_condSignal(UConditionVar *cond) {
- cond->fCV.notify_one();
+U_CAPI void U_EXPORT2
+umtx_unlock(UMutex* mutex)
+{
+ if (mutex == nullptr) {
+ mutex = &globalMutex;
+ }
+ mutex->unlock();
}
@@ -98,17 +133,6 @@ umtx_condSignal(UConditionVar *cond) {
*
*************************************************************************************************/
-static std::mutex &initMutex() {
- static std::mutex m;
- return m;
-}
-
-static std::condition_variable &initCondition() {
- static std::condition_variable cv;
- return cv;
-}
-
-
// 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.
@@ -119,8 +143,8 @@ static std::condition_variable &initCondition() {
//
U_COMMON_API UBool U_EXPORT2
umtx_initImplPreInit(UInitOnce &uio) {
- std::unique_lock<std::mutex> lock(initMutex());
-
+ std::call_once(*pInitFlag, umtx_init);
+ std::unique_lock<std::mutex> lock(*initMutex);
if (umtx_loadAcquire(uio.fState) == 0) {
umtx_storeRelease(uio.fState, 1);
return true; // Caller will next call the init function.
@@ -128,7 +152,7 @@ umtx_initImplPreInit(UInitOnce &uio) {
while (umtx_loadAcquire(uio.fState) == 1) {
// Another thread is currently running the initialization.
// Wait until it completes.
- initCondition().wait(lock);
+ initCondition->wait(lock);
}
U_ASSERT(uio.fState == 2);
return false;
@@ -145,10 +169,10 @@ umtx_initImplPreInit(UInitOnce &uio) {
U_COMMON_API void U_EXPORT2
umtx_initImplPostInit(UInitOnce &uio) {
{
- std::unique_lock<std::mutex> lock(initMutex());
+ std::unique_lock<std::mutex> lock(*initMutex);
umtx_storeRelease(uio.fState, 2);
}
- initCondition().notify_all();
+ initCondition->notify_all();
}
U_NAMESPACE_END