12e5b6d6dSopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 22e5b6d6dSopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 32e5b6d6dSopenharmony_ci/* 42e5b6d6dSopenharmony_ci****************************************************************************** 52e5b6d6dSopenharmony_ci* 62e5b6d6dSopenharmony_ci* Copyright (C) 1997-2016, International Business Machines 72e5b6d6dSopenharmony_ci* Corporation and others. All Rights Reserved. 82e5b6d6dSopenharmony_ci* 92e5b6d6dSopenharmony_ci****************************************************************************** 102e5b6d6dSopenharmony_ci* 112e5b6d6dSopenharmony_ci* File umutex.cpp 122e5b6d6dSopenharmony_ci* 132e5b6d6dSopenharmony_ci* Modification History: 142e5b6d6dSopenharmony_ci* 152e5b6d6dSopenharmony_ci* Date Name Description 162e5b6d6dSopenharmony_ci* 04/02/97 aliu Creation. 172e5b6d6dSopenharmony_ci* 04/07/99 srl updated 182e5b6d6dSopenharmony_ci* 05/13/99 stephen Changed to umutex (from cmutex). 192e5b6d6dSopenharmony_ci* 11/22/99 aliu Make non-global mutex autoinitialize [j151] 202e5b6d6dSopenharmony_ci****************************************************************************** 212e5b6d6dSopenharmony_ci*/ 222e5b6d6dSopenharmony_ci 232e5b6d6dSopenharmony_ci#include "umutex.h" 242e5b6d6dSopenharmony_ci 252e5b6d6dSopenharmony_ci#include "unicode/utypes.h" 262e5b6d6dSopenharmony_ci#include "uassert.h" 272e5b6d6dSopenharmony_ci#include "ucln_cmn.h" 282e5b6d6dSopenharmony_ci#include "cmemory.h" 292e5b6d6dSopenharmony_ci 302e5b6d6dSopenharmony_ciU_NAMESPACE_BEGIN 312e5b6d6dSopenharmony_ci 322e5b6d6dSopenharmony_ci 332e5b6d6dSopenharmony_ci#if defined(U_USER_MUTEX_CPP) 342e5b6d6dSopenharmony_ci// Support for including an alternate implementation of mutexes has been withdrawn. 352e5b6d6dSopenharmony_ci// See issue ICU-20185. 362e5b6d6dSopenharmony_ci#error U_USER_MUTEX_CPP not supported 372e5b6d6dSopenharmony_ci#endif 382e5b6d6dSopenharmony_ci 392e5b6d6dSopenharmony_ci 402e5b6d6dSopenharmony_ci/************************************************************************************************* 412e5b6d6dSopenharmony_ci * 422e5b6d6dSopenharmony_ci * ICU Mutex wrappers. 432e5b6d6dSopenharmony_ci * 442e5b6d6dSopenharmony_ci *************************************************************************************************/ 452e5b6d6dSopenharmony_ci 462e5b6d6dSopenharmony_cinamespace { 472e5b6d6dSopenharmony_cistd::mutex *initMutex; 482e5b6d6dSopenharmony_cistd::condition_variable *initCondition; 492e5b6d6dSopenharmony_ci 502e5b6d6dSopenharmony_ci// The ICU global mutex. 512e5b6d6dSopenharmony_ci// Used when ICU implementation code passes nullptr for the mutex pointer. 522e5b6d6dSopenharmony_ciUMutex globalMutex; 532e5b6d6dSopenharmony_ci 542e5b6d6dSopenharmony_cistd::once_flag initFlag; 552e5b6d6dSopenharmony_cistd::once_flag *pInitFlag = &initFlag; 562e5b6d6dSopenharmony_ci 572e5b6d6dSopenharmony_ci} // Anonymous namespace 582e5b6d6dSopenharmony_ci 592e5b6d6dSopenharmony_ciU_CDECL_BEGIN 602e5b6d6dSopenharmony_cistatic UBool U_CALLCONV umtx_cleanup() { 612e5b6d6dSopenharmony_ci initMutex->~mutex(); 622e5b6d6dSopenharmony_ci initCondition->~condition_variable(); 632e5b6d6dSopenharmony_ci UMutex::cleanup(); 642e5b6d6dSopenharmony_ci 652e5b6d6dSopenharmony_ci // Reset the once_flag, by destructing it and creating a fresh one in its place. 662e5b6d6dSopenharmony_ci // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once(). 672e5b6d6dSopenharmony_ci pInitFlag->~once_flag(); 682e5b6d6dSopenharmony_ci pInitFlag = new(&initFlag) std::once_flag(); 692e5b6d6dSopenharmony_ci return true; 702e5b6d6dSopenharmony_ci} 712e5b6d6dSopenharmony_ci 722e5b6d6dSopenharmony_cistatic void U_CALLCONV umtx_init() { 732e5b6d6dSopenharmony_ci initMutex = STATIC_NEW(std::mutex); 742e5b6d6dSopenharmony_ci initCondition = STATIC_NEW(std::condition_variable); 752e5b6d6dSopenharmony_ci ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup); 762e5b6d6dSopenharmony_ci} 772e5b6d6dSopenharmony_ciU_CDECL_END 782e5b6d6dSopenharmony_ci 792e5b6d6dSopenharmony_ci 802e5b6d6dSopenharmony_cistd::mutex *UMutex::getMutex() { 812e5b6d6dSopenharmony_ci std::mutex *retPtr = fMutex.load(std::memory_order_acquire); 822e5b6d6dSopenharmony_ci if (retPtr == nullptr) { 832e5b6d6dSopenharmony_ci std::call_once(*pInitFlag, umtx_init); 842e5b6d6dSopenharmony_ci std::lock_guard<std::mutex> guard(*initMutex); 852e5b6d6dSopenharmony_ci retPtr = fMutex.load(std::memory_order_acquire); 862e5b6d6dSopenharmony_ci if (retPtr == nullptr) { 872e5b6d6dSopenharmony_ci fMutex = new(fStorage) std::mutex(); 882e5b6d6dSopenharmony_ci retPtr = fMutex; 892e5b6d6dSopenharmony_ci fListLink = gListHead; 902e5b6d6dSopenharmony_ci gListHead = this; 912e5b6d6dSopenharmony_ci } 922e5b6d6dSopenharmony_ci } 932e5b6d6dSopenharmony_ci U_ASSERT(retPtr != nullptr); 942e5b6d6dSopenharmony_ci return retPtr; 952e5b6d6dSopenharmony_ci} 962e5b6d6dSopenharmony_ci 972e5b6d6dSopenharmony_ciUMutex *UMutex::gListHead = nullptr; 982e5b6d6dSopenharmony_ci 992e5b6d6dSopenharmony_civoid UMutex::cleanup() { 1002e5b6d6dSopenharmony_ci UMutex *next = nullptr; 1012e5b6d6dSopenharmony_ci for (UMutex *m = gListHead; m != nullptr; m = next) { 1022e5b6d6dSopenharmony_ci (*m->fMutex).~mutex(); 1032e5b6d6dSopenharmony_ci m->fMutex = nullptr; 1042e5b6d6dSopenharmony_ci next = m->fListLink; 1052e5b6d6dSopenharmony_ci m->fListLink = nullptr; 1062e5b6d6dSopenharmony_ci } 1072e5b6d6dSopenharmony_ci gListHead = nullptr; 1082e5b6d6dSopenharmony_ci} 1092e5b6d6dSopenharmony_ci 1102e5b6d6dSopenharmony_ci 1112e5b6d6dSopenharmony_ciU_CAPI void U_EXPORT2 1122e5b6d6dSopenharmony_ciumtx_lock(UMutex *mutex) { 1132e5b6d6dSopenharmony_ci if (mutex == nullptr) { 1142e5b6d6dSopenharmony_ci mutex = &globalMutex; 1152e5b6d6dSopenharmony_ci } 1162e5b6d6dSopenharmony_ci mutex->lock(); 1172e5b6d6dSopenharmony_ci} 1182e5b6d6dSopenharmony_ci 1192e5b6d6dSopenharmony_ci 1202e5b6d6dSopenharmony_ciU_CAPI void U_EXPORT2 1212e5b6d6dSopenharmony_ciumtx_unlock(UMutex* mutex) 1222e5b6d6dSopenharmony_ci{ 1232e5b6d6dSopenharmony_ci if (mutex == nullptr) { 1242e5b6d6dSopenharmony_ci mutex = &globalMutex; 1252e5b6d6dSopenharmony_ci } 1262e5b6d6dSopenharmony_ci mutex->unlock(); 1272e5b6d6dSopenharmony_ci} 1282e5b6d6dSopenharmony_ci 1292e5b6d6dSopenharmony_ci 1302e5b6d6dSopenharmony_ci/************************************************************************************************* 1312e5b6d6dSopenharmony_ci * 1322e5b6d6dSopenharmony_ci * UInitOnce Implementation 1332e5b6d6dSopenharmony_ci * 1342e5b6d6dSopenharmony_ci *************************************************************************************************/ 1352e5b6d6dSopenharmony_ci 1362e5b6d6dSopenharmony_ci// This function is called when a test of a UInitOnce::fState reveals that 1372e5b6d6dSopenharmony_ci// initialization has not completed, that we either need to call the init 1382e5b6d6dSopenharmony_ci// function on this thread, or wait for some other thread to complete. 1392e5b6d6dSopenharmony_ci// 1402e5b6d6dSopenharmony_ci// The actual call to the init function is made inline by template code 1412e5b6d6dSopenharmony_ci// that knows the C++ types involved. This function returns true if 1422e5b6d6dSopenharmony_ci// the caller needs to call the Init function. 1432e5b6d6dSopenharmony_ci// 1442e5b6d6dSopenharmony_ciU_COMMON_API UBool U_EXPORT2 1452e5b6d6dSopenharmony_ciumtx_initImplPreInit(UInitOnce &uio) { 1462e5b6d6dSopenharmony_ci std::call_once(*pInitFlag, umtx_init); 1472e5b6d6dSopenharmony_ci std::unique_lock<std::mutex> lock(*initMutex); 1482e5b6d6dSopenharmony_ci if (umtx_loadAcquire(uio.fState) == 0) { 1492e5b6d6dSopenharmony_ci umtx_storeRelease(uio.fState, 1); 1502e5b6d6dSopenharmony_ci return true; // Caller will next call the init function. 1512e5b6d6dSopenharmony_ci } else { 1522e5b6d6dSopenharmony_ci while (umtx_loadAcquire(uio.fState) == 1) { 1532e5b6d6dSopenharmony_ci // Another thread is currently running the initialization. 1542e5b6d6dSopenharmony_ci // Wait until it completes. 1552e5b6d6dSopenharmony_ci initCondition->wait(lock); 1562e5b6d6dSopenharmony_ci } 1572e5b6d6dSopenharmony_ci U_ASSERT(uio.fState == 2); 1582e5b6d6dSopenharmony_ci return false; 1592e5b6d6dSopenharmony_ci } 1602e5b6d6dSopenharmony_ci} 1612e5b6d6dSopenharmony_ci 1622e5b6d6dSopenharmony_ci 1632e5b6d6dSopenharmony_ci// This function is called by the thread that ran an initialization function, 1642e5b6d6dSopenharmony_ci// just after completing the function. 1652e5b6d6dSopenharmony_ci// Some threads may be waiting on the condition, requiring the broadcast wakeup. 1662e5b6d6dSopenharmony_ci// Some threads may be racing to test the fState variable outside of the mutex, 1672e5b6d6dSopenharmony_ci// requiring the use of store/release when changing its value. 1682e5b6d6dSopenharmony_ci 1692e5b6d6dSopenharmony_ciU_COMMON_API void U_EXPORT2 1702e5b6d6dSopenharmony_ciumtx_initImplPostInit(UInitOnce &uio) { 1712e5b6d6dSopenharmony_ci { 1722e5b6d6dSopenharmony_ci std::unique_lock<std::mutex> lock(*initMutex); 1732e5b6d6dSopenharmony_ci umtx_storeRelease(uio.fState, 2); 1742e5b6d6dSopenharmony_ci } 1752e5b6d6dSopenharmony_ci initCondition->notify_all(); 1762e5b6d6dSopenharmony_ci} 1772e5b6d6dSopenharmony_ci 1782e5b6d6dSopenharmony_ciU_NAMESPACE_END 1792e5b6d6dSopenharmony_ci 1802e5b6d6dSopenharmony_ci/************************************************************************************************* 1812e5b6d6dSopenharmony_ci * 1822e5b6d6dSopenharmony_ci * Deprecated functions for setting user mutexes. 1832e5b6d6dSopenharmony_ci * 1842e5b6d6dSopenharmony_ci *************************************************************************************************/ 1852e5b6d6dSopenharmony_ci 1862e5b6d6dSopenharmony_ciU_DEPRECATED void U_EXPORT2 1872e5b6d6dSopenharmony_ciu_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *, 1882e5b6d6dSopenharmony_ci UMtxFn *, UMtxFn *, UErrorCode *status) { 1892e5b6d6dSopenharmony_ci if (U_SUCCESS(*status)) { 1902e5b6d6dSopenharmony_ci *status = U_UNSUPPORTED_ERROR; 1912e5b6d6dSopenharmony_ci } 1922e5b6d6dSopenharmony_ci return; 1932e5b6d6dSopenharmony_ci} 1942e5b6d6dSopenharmony_ci 1952e5b6d6dSopenharmony_ci 1962e5b6d6dSopenharmony_ci 1972e5b6d6dSopenharmony_ciU_DEPRECATED void U_EXPORT2 1982e5b6d6dSopenharmony_ciu_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *, 1992e5b6d6dSopenharmony_ci UErrorCode *status) { 2002e5b6d6dSopenharmony_ci if (U_SUCCESS(*status)) { 2012e5b6d6dSopenharmony_ci *status = U_UNSUPPORTED_ERROR; 2022e5b6d6dSopenharmony_ci } 2032e5b6d6dSopenharmony_ci return; 2042e5b6d6dSopenharmony_ci} 205