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