123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- // © 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.
- *
- *************************************************************************************************/
- 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
- 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;
- }
- 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;
- }
- 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;
- }
- gListHead = nullptr;
- }
- U_CAPI void U_EXPORT2
- umtx_lock(UMutex *mutex) {
- if (mutex == nullptr) {
- mutex = &globalMutex;
- }
- mutex->lock();
- }
- U_CAPI void U_EXPORT2
- umtx_unlock(UMutex* mutex)
- {
- if (mutex == nullptr) {
- mutex = &globalMutex;
- }
- mutex->unlock();
- }
- /*************************************************************************************************
- *
- * 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) {
- 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.
- } else {
- 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);
- 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) {
- {
- std::unique_lock<std::mutex> lock(*initMutex);
- umtx_storeRelease(uio.fState, 2);
- }
- initCondition->notify_all();
- }
- 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;
- }
- }
- U_DEPRECATED void U_EXPORT2
- u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
- UErrorCode *status) {
- if (U_SUCCESS(*status)) {
- *status = U_UNSUPPORTED_ERROR;
- }
- }
|