11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci/* 41cb0ef41Sopenharmony_ci****************************************************************************** 51cb0ef41Sopenharmony_ci* 61cb0ef41Sopenharmony_ci* Copyright (C) 1997-2016, International Business Machines 71cb0ef41Sopenharmony_ci* Corporation and others. All Rights Reserved. 81cb0ef41Sopenharmony_ci* 91cb0ef41Sopenharmony_ci****************************************************************************** 101cb0ef41Sopenharmony_ci* 111cb0ef41Sopenharmony_ci* File umutex.cpp 121cb0ef41Sopenharmony_ci* 131cb0ef41Sopenharmony_ci* Modification History: 141cb0ef41Sopenharmony_ci* 151cb0ef41Sopenharmony_ci* Date Name Description 161cb0ef41Sopenharmony_ci* 04/02/97 aliu Creation. 171cb0ef41Sopenharmony_ci* 04/07/99 srl updated 181cb0ef41Sopenharmony_ci* 05/13/99 stephen Changed to umutex (from cmutex). 191cb0ef41Sopenharmony_ci* 11/22/99 aliu Make non-global mutex autoinitialize [j151] 201cb0ef41Sopenharmony_ci****************************************************************************** 211cb0ef41Sopenharmony_ci*/ 221cb0ef41Sopenharmony_ci 231cb0ef41Sopenharmony_ci#include "umutex.h" 241cb0ef41Sopenharmony_ci 251cb0ef41Sopenharmony_ci#include "unicode/utypes.h" 261cb0ef41Sopenharmony_ci#include "uassert.h" 271cb0ef41Sopenharmony_ci#include "ucln_cmn.h" 281cb0ef41Sopenharmony_ci#include "cmemory.h" 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci#if defined(U_USER_MUTEX_CPP) 341cb0ef41Sopenharmony_ci// Support for including an alternate implementation of mutexes has been withdrawn. 351cb0ef41Sopenharmony_ci// See issue ICU-20185. 361cb0ef41Sopenharmony_ci#error U_USER_MUTEX_CPP not supported 371cb0ef41Sopenharmony_ci#endif 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_ci/************************************************************************************************* 411cb0ef41Sopenharmony_ci * 421cb0ef41Sopenharmony_ci * ICU Mutex wrappers. 431cb0ef41Sopenharmony_ci * 441cb0ef41Sopenharmony_ci *************************************************************************************************/ 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_cinamespace { 471cb0ef41Sopenharmony_cistd::mutex *initMutex; 481cb0ef41Sopenharmony_cistd::condition_variable *initCondition; 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci// The ICU global mutex. 511cb0ef41Sopenharmony_ci// Used when ICU implementation code passes nullptr for the mutex pointer. 521cb0ef41Sopenharmony_ciUMutex globalMutex; 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_cistd::once_flag initFlag; 551cb0ef41Sopenharmony_cistd::once_flag *pInitFlag = &initFlag; 561cb0ef41Sopenharmony_ci 571cb0ef41Sopenharmony_ci} // Anonymous namespace 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciU_CDECL_BEGIN 601cb0ef41Sopenharmony_cistatic UBool U_CALLCONV umtx_cleanup() { 611cb0ef41Sopenharmony_ci initMutex->~mutex(); 621cb0ef41Sopenharmony_ci initCondition->~condition_variable(); 631cb0ef41Sopenharmony_ci UMutex::cleanup(); 641cb0ef41Sopenharmony_ci 651cb0ef41Sopenharmony_ci // Reset the once_flag, by destructing it and creating a fresh one in its place. 661cb0ef41Sopenharmony_ci // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once(). 671cb0ef41Sopenharmony_ci pInitFlag->~once_flag(); 681cb0ef41Sopenharmony_ci pInitFlag = new(&initFlag) std::once_flag(); 691cb0ef41Sopenharmony_ci return true; 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_cistatic void U_CALLCONV umtx_init() { 731cb0ef41Sopenharmony_ci initMutex = STATIC_NEW(std::mutex); 741cb0ef41Sopenharmony_ci initCondition = STATIC_NEW(std::condition_variable); 751cb0ef41Sopenharmony_ci ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup); 761cb0ef41Sopenharmony_ci} 771cb0ef41Sopenharmony_ciU_CDECL_END 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_cistd::mutex *UMutex::getMutex() { 811cb0ef41Sopenharmony_ci std::mutex *retPtr = fMutex.load(std::memory_order_acquire); 821cb0ef41Sopenharmony_ci if (retPtr == nullptr) { 831cb0ef41Sopenharmony_ci std::call_once(*pInitFlag, umtx_init); 841cb0ef41Sopenharmony_ci std::lock_guard<std::mutex> guard(*initMutex); 851cb0ef41Sopenharmony_ci retPtr = fMutex.load(std::memory_order_acquire); 861cb0ef41Sopenharmony_ci if (retPtr == nullptr) { 871cb0ef41Sopenharmony_ci fMutex = new(fStorage) std::mutex(); 881cb0ef41Sopenharmony_ci retPtr = fMutex; 891cb0ef41Sopenharmony_ci fListLink = gListHead; 901cb0ef41Sopenharmony_ci gListHead = this; 911cb0ef41Sopenharmony_ci } 921cb0ef41Sopenharmony_ci } 931cb0ef41Sopenharmony_ci U_ASSERT(retPtr != nullptr); 941cb0ef41Sopenharmony_ci return retPtr; 951cb0ef41Sopenharmony_ci} 961cb0ef41Sopenharmony_ci 971cb0ef41Sopenharmony_ciUMutex *UMutex::gListHead = nullptr; 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_civoid UMutex::cleanup() { 1001cb0ef41Sopenharmony_ci UMutex *next = nullptr; 1011cb0ef41Sopenharmony_ci for (UMutex *m = gListHead; m != nullptr; m = next) { 1021cb0ef41Sopenharmony_ci (*m->fMutex).~mutex(); 1031cb0ef41Sopenharmony_ci m->fMutex = nullptr; 1041cb0ef41Sopenharmony_ci next = m->fListLink; 1051cb0ef41Sopenharmony_ci m->fListLink = nullptr; 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci gListHead = nullptr; 1081cb0ef41Sopenharmony_ci} 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 1121cb0ef41Sopenharmony_ciumtx_lock(UMutex *mutex) { 1131cb0ef41Sopenharmony_ci if (mutex == nullptr) { 1141cb0ef41Sopenharmony_ci mutex = &globalMutex; 1151cb0ef41Sopenharmony_ci } 1161cb0ef41Sopenharmony_ci mutex->lock(); 1171cb0ef41Sopenharmony_ci} 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ciU_CAPI void U_EXPORT2 1211cb0ef41Sopenharmony_ciumtx_unlock(UMutex* mutex) 1221cb0ef41Sopenharmony_ci{ 1231cb0ef41Sopenharmony_ci if (mutex == nullptr) { 1241cb0ef41Sopenharmony_ci mutex = &globalMutex; 1251cb0ef41Sopenharmony_ci } 1261cb0ef41Sopenharmony_ci mutex->unlock(); 1271cb0ef41Sopenharmony_ci} 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci/************************************************************************************************* 1311cb0ef41Sopenharmony_ci * 1321cb0ef41Sopenharmony_ci * UInitOnce Implementation 1331cb0ef41Sopenharmony_ci * 1341cb0ef41Sopenharmony_ci *************************************************************************************************/ 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci// This function is called when a test of a UInitOnce::fState reveals that 1371cb0ef41Sopenharmony_ci// initialization has not completed, that we either need to call the init 1381cb0ef41Sopenharmony_ci// function on this thread, or wait for some other thread to complete. 1391cb0ef41Sopenharmony_ci// 1401cb0ef41Sopenharmony_ci// The actual call to the init function is made inline by template code 1411cb0ef41Sopenharmony_ci// that knows the C++ types involved. This function returns true if 1421cb0ef41Sopenharmony_ci// the caller needs to call the Init function. 1431cb0ef41Sopenharmony_ci// 1441cb0ef41Sopenharmony_ciU_COMMON_API UBool U_EXPORT2 1451cb0ef41Sopenharmony_ciumtx_initImplPreInit(UInitOnce &uio) { 1461cb0ef41Sopenharmony_ci std::call_once(*pInitFlag, umtx_init); 1471cb0ef41Sopenharmony_ci std::unique_lock<std::mutex> lock(*initMutex); 1481cb0ef41Sopenharmony_ci if (umtx_loadAcquire(uio.fState) == 0) { 1491cb0ef41Sopenharmony_ci umtx_storeRelease(uio.fState, 1); 1501cb0ef41Sopenharmony_ci return true; // Caller will next call the init function. 1511cb0ef41Sopenharmony_ci } else { 1521cb0ef41Sopenharmony_ci while (umtx_loadAcquire(uio.fState) == 1) { 1531cb0ef41Sopenharmony_ci // Another thread is currently running the initialization. 1541cb0ef41Sopenharmony_ci // Wait until it completes. 1551cb0ef41Sopenharmony_ci initCondition->wait(lock); 1561cb0ef41Sopenharmony_ci } 1571cb0ef41Sopenharmony_ci U_ASSERT(uio.fState == 2); 1581cb0ef41Sopenharmony_ci return false; 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci} 1611cb0ef41Sopenharmony_ci 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci// This function is called by the thread that ran an initialization function, 1641cb0ef41Sopenharmony_ci// just after completing the function. 1651cb0ef41Sopenharmony_ci// Some threads may be waiting on the condition, requiring the broadcast wakeup. 1661cb0ef41Sopenharmony_ci// Some threads may be racing to test the fState variable outside of the mutex, 1671cb0ef41Sopenharmony_ci// requiring the use of store/release when changing its value. 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ciU_COMMON_API void U_EXPORT2 1701cb0ef41Sopenharmony_ciumtx_initImplPostInit(UInitOnce &uio) { 1711cb0ef41Sopenharmony_ci { 1721cb0ef41Sopenharmony_ci std::unique_lock<std::mutex> lock(*initMutex); 1731cb0ef41Sopenharmony_ci umtx_storeRelease(uio.fState, 2); 1741cb0ef41Sopenharmony_ci } 1751cb0ef41Sopenharmony_ci initCondition->notify_all(); 1761cb0ef41Sopenharmony_ci} 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ciU_NAMESPACE_END 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci/************************************************************************************************* 1811cb0ef41Sopenharmony_ci * 1821cb0ef41Sopenharmony_ci * Deprecated functions for setting user mutexes. 1831cb0ef41Sopenharmony_ci * 1841cb0ef41Sopenharmony_ci *************************************************************************************************/ 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_ciU_DEPRECATED void U_EXPORT2 1871cb0ef41Sopenharmony_ciu_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *, 1881cb0ef41Sopenharmony_ci UMtxFn *, UMtxFn *, UErrorCode *status) { 1891cb0ef41Sopenharmony_ci if (U_SUCCESS(*status)) { 1901cb0ef41Sopenharmony_ci *status = U_UNSUPPORTED_ERROR; 1911cb0ef41Sopenharmony_ci } 1921cb0ef41Sopenharmony_ci return; 1931cb0ef41Sopenharmony_ci} 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ciU_DEPRECATED void U_EXPORT2 1981cb0ef41Sopenharmony_ciu_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *, 1991cb0ef41Sopenharmony_ci UErrorCode *status) { 2001cb0ef41Sopenharmony_ci if (U_SUCCESS(*status)) { 2011cb0ef41Sopenharmony_ci *status = U_UNSUPPORTED_ERROR; 2021cb0ef41Sopenharmony_ci } 2031cb0ef41Sopenharmony_ci return; 2041cb0ef41Sopenharmony_ci} 205