tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

umutex.cpp (6182B)


      1 // © 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 ******************************************************************************
      5 *
      6 *   Copyright (C) 1997-2016, International Business Machines
      7 *   Corporation and others.  All Rights Reserved.
      8 *
      9 ******************************************************************************
     10 *
     11 * File umutex.cpp
     12 *
     13 * Modification History:
     14 *
     15 *   Date        Name        Description
     16 *   04/02/97    aliu        Creation.
     17 *   04/07/99    srl         updated
     18 *   05/13/99    stephen     Changed to umutex (from cmutex).
     19 *   11/22/99    aliu        Make non-global mutex autoinitialize [j151]
     20 ******************************************************************************
     21 */
     22 
     23 #include "umutex.h"
     24 
     25 #include "unicode/utypes.h"
     26 #include "uassert.h"
     27 #include "ucln_cmn.h"
     28 #include "cmemory.h"
     29 
     30 U_NAMESPACE_BEGIN
     31 
     32 
     33 #if defined(U_USER_MUTEX_CPP)
     34 // Support for including an alternate implementation of mutexes has been withdrawn.
     35 // See issue ICU-20185.
     36 #error U_USER_MUTEX_CPP not supported
     37 #endif
     38 
     39 
     40 /*************************************************************************************************
     41 *
     42 *  ICU Mutex wrappers.
     43 *
     44 *************************************************************************************************/
     45 
     46 #ifndef __wasi__
     47 namespace {
     48 std::mutex *initMutex;
     49 std::condition_variable *initCondition;
     50 
     51 // The ICU global mutex.
     52 // Used when ICU implementation code passes nullptr for the mutex pointer.
     53 UMutex globalMutex;
     54 
     55 std::once_flag initFlag;
     56 std::once_flag *pInitFlag = &initFlag;
     57 
     58 }  // Anonymous namespace
     59 #endif
     60 
     61 U_CDECL_BEGIN
     62 static UBool U_CALLCONV umtx_cleanup() {
     63 #ifndef __wasi__
     64    initMutex->~mutex();
     65    initCondition->~condition_variable();
     66    UMutex::cleanup();
     67 
     68    // Reset the once_flag, by destructing it and creating a fresh one in its place.
     69    // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
     70    pInitFlag->~once_flag();
     71    pInitFlag = new(&initFlag) std::once_flag();
     72 #endif
     73    return true;
     74 }
     75 
     76 static void U_CALLCONV umtx_init() {
     77 #ifndef __wasi__
     78    initMutex = STATIC_NEW(std::mutex);
     79    initCondition = STATIC_NEW(std::condition_variable);
     80    ucln_common_registerCleanup(UCLN_COMMON_MUTEX, umtx_cleanup);
     81 #endif
     82 }
     83 U_CDECL_END
     84 
     85 
     86 #ifndef __wasi__
     87 std::mutex *UMutex::getMutex() {
     88    std::mutex *retPtr = fMutex.load(std::memory_order_acquire);
     89    if (retPtr == nullptr) {
     90        std::call_once(*pInitFlag, umtx_init);
     91        std::lock_guard<std::mutex> guard(*initMutex);
     92        retPtr = fMutex.load(std::memory_order_acquire);
     93        if (retPtr == nullptr) {
     94            fMutex = new(fStorage) std::mutex();
     95            retPtr = fMutex;
     96            fListLink = gListHead;
     97            gListHead = this;
     98        }
     99    }
    100    U_ASSERT(retPtr != nullptr);
    101    return retPtr;
    102 }
    103 #endif
    104 
    105 UMutex *UMutex::gListHead = nullptr;
    106 
    107 void UMutex::cleanup() {
    108    UMutex *next = nullptr;
    109    for (UMutex *m = gListHead; m != nullptr; m = next) {
    110 #ifndef __wasi__
    111        (*m->fMutex).~mutex();
    112        m->fMutex = nullptr;
    113 #endif
    114        next = m->fListLink;
    115        m->fListLink = nullptr;
    116    }
    117    gListHead = nullptr;
    118 }
    119 
    120 
    121 U_CAPI void  U_EXPORT2
    122 umtx_lock(UMutex *mutex) {
    123 #ifndef __wasi__
    124    if (mutex == nullptr) {
    125        mutex = &globalMutex;
    126    }
    127    mutex->lock();
    128 #endif
    129 }
    130 
    131 
    132 U_CAPI void  U_EXPORT2
    133 umtx_unlock(UMutex* mutex)
    134 {
    135 #ifndef __wasi__
    136    if (mutex == nullptr) {
    137        mutex = &globalMutex;
    138    }
    139    mutex->unlock();
    140 #endif
    141 }
    142 
    143 
    144 /*************************************************************************************************
    145 *
    146 *  UInitOnce Implementation
    147 *
    148 *************************************************************************************************/
    149 
    150 // This function is called when a test of a UInitOnce::fState reveals that
    151 //   initialization has not completed, that we either need to call the init
    152 //   function on this thread, or wait for some other thread to complete.
    153 //
    154 // The actual call to the init function is made inline by template code
    155 //   that knows the C++ types involved. This function returns true if
    156 //   the caller needs to call the Init function.
    157 //
    158 U_COMMON_API UBool U_EXPORT2
    159 umtx_initImplPreInit(UInitOnce &uio) {
    160 #ifndef __wasi__
    161    std::call_once(*pInitFlag, umtx_init);
    162    std::unique_lock<std::mutex> lock(*initMutex);
    163 #endif
    164    if (umtx_loadAcquire(uio.fState) == 0) {
    165        umtx_storeRelease(uio.fState, 1);
    166        return true;      // Caller will next call the init function.
    167    } else {
    168 #ifndef __wasi__
    169        while (umtx_loadAcquire(uio.fState) == 1) {
    170            // Another thread is currently running the initialization.
    171            // Wait until it completes.
    172            initCondition->wait(lock);
    173        }
    174        U_ASSERT(uio.fState == 2);
    175 #endif
    176        return false;
    177    }
    178 }
    179 
    180 
    181 // This function is called by the thread that ran an initialization function,
    182 // just after completing the function.
    183 //   Some threads may be waiting on the condition, requiring the broadcast wakeup.
    184 //   Some threads may be racing to test the fState variable outside of the mutex,
    185 //   requiring the use of store/release when changing its value.
    186 
    187 U_COMMON_API void U_EXPORT2
    188 umtx_initImplPostInit(UInitOnce &uio) {
    189 #ifndef __wasi__
    190    {
    191        std::unique_lock<std::mutex> lock(*initMutex);
    192        umtx_storeRelease(uio.fState, 2);
    193    }
    194    initCondition->notify_all();
    195 #endif
    196 }
    197 
    198 U_NAMESPACE_END
    199 
    200 /*************************************************************************************************
    201 *
    202 *  Deprecated functions for setting user mutexes.
    203 *
    204 *************************************************************************************************/
    205 
    206 U_DEPRECATED void U_EXPORT2
    207 u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
    208                    UMtxFn *,  UMtxFn *, UErrorCode *status) {
    209    if (U_SUCCESS(*status)) {
    210        *status = U_UNSUPPORTED_ERROR;
    211    }
    212 }
    213 
    214 
    215 
    216 U_DEPRECATED void U_EXPORT2
    217 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
    218                           UErrorCode *status) {
    219    if (U_SUCCESS(*status)) {
    220        *status = U_UNSUPPORTED_ERROR;
    221    }
    222 }