xref: /third_party/icu/icu4c/source/common/umutex.cpp (revision 2e5b6d6d)
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