12e5b6d6dSopenharmony_ci---
22e5b6d6dSopenharmony_cilayout: default
32e5b6d6dSopenharmony_cititle: Custom ICU4C Synchronization
42e5b6d6dSopenharmony_cinav_order: 3
52e5b6d6dSopenharmony_ciparent: Contributors
62e5b6d6dSopenharmony_ci---
72e5b6d6dSopenharmony_ci<!--
82e5b6d6dSopenharmony_ci© 2020 and later: Unicode, Inc. and others.
92e5b6d6dSopenharmony_ciLicense & terms of use: http://www.unicode.org/copyright.html
102e5b6d6dSopenharmony_ci-->
112e5b6d6dSopenharmony_ci
122e5b6d6dSopenharmony_ci# Custom ICU4C Synchronization
132e5b6d6dSopenharmony_ci{: .no_toc }
142e5b6d6dSopenharmony_ci
152e5b6d6dSopenharmony_ci## Contents
162e5b6d6dSopenharmony_ci{: .no_toc .text-delta }
172e5b6d6dSopenharmony_ci
182e5b6d6dSopenharmony_ci1. TOC
192e5b6d6dSopenharmony_ci{:toc}
202e5b6d6dSopenharmony_ci
212e5b6d6dSopenharmony_ci---
222e5b6d6dSopenharmony_ci
232e5b6d6dSopenharmony_ci> :warning: ***Support for including an alternate implementation of atomic and mutex
242e5b6d6dSopenharmony_ci> operations has been withdrawn and removed from ICU4C.***
252e5b6d6dSopenharmony_ci> See issue [ICU-20185](https://unicode-org.atlassian.net/browse/ICU-20185).
262e5b6d6dSopenharmony_ci
272e5b6d6dSopenharmony_ci### Build Time User Provided Synchronization
282e5b6d6dSopenharmony_ci
292e5b6d6dSopenharmony_ciBuild time user synchronization provides a mechanism for platforms with special
302e5b6d6dSopenharmony_cirequirements to provide their own mutex and one-time initialization
312e5b6d6dSopenharmony_ciimplementations to ICU. This facility was introduced in ICU 53. It may change
322e5b6d6dSopenharmony_ciover time.
332e5b6d6dSopenharmony_ci
342e5b6d6dSopenharmony_ciThe alternative implementations are compiled directly into the ICU libraries.
352e5b6d6dSopenharmony_ciAlternative implementations cannot be plugged in at run time.
362e5b6d6dSopenharmony_ci
372e5b6d6dSopenharmony_ciThe tables below show the items that must be defined by a custom ICU
382e5b6d6dSopenharmony_cisynchronization implementation. The list includes both functions that are used
392e5b6d6dSopenharmony_cithroughout ICU code and additional functions are for internal by other ICU
402e5b6d6dSopenharmony_cisynchronization primitives.
412e5b6d6dSopenharmony_ci
422e5b6d6dSopenharmony_ci**Low Level Atomics**, a set of platform or compiler dependent typedefs and
432e5b6d6dSopenharmony_ciinlines. Provided in the internal header file
442e5b6d6dSopenharmony_ci[`umutex.h`](https://github.com/unicode-org/icu/blob/main/icu4c/source/common/umutex.h).
452e5b6d6dSopenharmony_ci
462e5b6d6dSopenharmony_ci| Type/Function                                           | Description                                                                   |
472e5b6d6dSopenharmony_ci|---------------------------------------------------------|-------------------------------------------------------------------------------|
482e5b6d6dSopenharmony_ci| `typedef u_atomic_int32_t`                              | A 32 bit integer that will work with low level atomic operations. (`typedef`) |
492e5b6d6dSopenharmony_ci| `umtx_loadAcquire(u_atomic_int32_t &var)`               |                                                                               |
502e5b6d6dSopenharmony_ci| `umtx_storeRelease(u_atomic_int32_t &var, int32_t val)` |                                                                               |
512e5b6d6dSopenharmony_ci| `umtx_atomic_inc(u_atomic_int32_t &var)`                |                                                                               |
522e5b6d6dSopenharmony_ci| `umtx_atomic_dec(u_atomic_int32_t &var)`                |                                                                               |
532e5b6d6dSopenharmony_ci
542e5b6d6dSopenharmony_ci**Mutexes**. Type declarations for ICU mutex wrappers. Provided in a header file.
552e5b6d6dSopenharmony_ci
562e5b6d6dSopenharmony_ci| Type                  | Description                                                                                       |
572e5b6d6dSopenharmony_ci|-----------------------|---------------------------------------------------------------------------------------------------|
582e5b6d6dSopenharmony_ci| `struct UMutex`       | An ICU mutex. All instances will be static. Typically just contains an underlying platform mutex. |
592e5b6d6dSopenharmony_ci| `U_MUTEX_INITIALIZER` | A C style initializer for a static instance of a `UMutex`.                                          |
602e5b6d6dSopenharmony_ci
612e5b6d6dSopenharmony_ci**Mutex and InitOnce implementations**. Out-of-line platform-specific code.
622e5b6d6dSopenharmony_ciProvided in a .cpp file.
632e5b6d6dSopenharmony_ci
642e5b6d6dSopenharmony_ci| Function                                | Description                                |
652e5b6d6dSopenharmony_ci|-----------------------------------------|--------------------------------------------|
662e5b6d6dSopenharmony_ci| `umtx_lock(UMutex *mutex)`              | Lock a mutex.                              |
672e5b6d6dSopenharmony_ci| `umtx_unlock(UMutex* mutex)`            | Unlock a mutex.                            |
682e5b6d6dSopenharmony_ci| `umtx_initImplPreInit(UInitOnce &uio)`  | `umtx_initOnce()` implementation function. |
692e5b6d6dSopenharmony_ci| `umtx_initImplPostInit(UInitOnce &uio)` | `umtx_initOnce()` implementation function. |
702e5b6d6dSopenharmony_ci
712e5b6d6dSopenharmony_ci`UInitOnce` and `umtx_initOnce()` are used internally by ICU for thread-safe
722e5b6d6dSopenharmony_cione-time initialization. Their implementation is split into a
732e5b6d6dSopenharmony_ciplatform-independent part (contained in
742e5b6d6dSopenharmony_ci[`umutex.h`](https://github.com/unicode-org/icu/blob/main/icu4c/source/common/umutex.h)),
752e5b6d6dSopenharmony_ciand the pair of platform-dependent implementation functions listed above.
762e5b6d6dSopenharmony_ci
772e5b6d6dSopenharmony_ci**Build Setup**
782e5b6d6dSopenharmony_ci
792e5b6d6dSopenharmony_ciCompiler preprocessor variables are used to name the custom files to be included
802e5b6d6dSopenharmony_ciin the ICU build. If defined, the files are included at the top of the normal
812e5b6d6dSopenharmony_ciplatform `#ifdef` chains in the ICU sources, and effectively define a new
822e5b6d6dSopenharmony_ciplatform.
832e5b6d6dSopenharmony_ci
842e5b6d6dSopenharmony_ci| Macro              | Description                                             |
852e5b6d6dSopenharmony_ci|--------------------|---------------------------------------------------------|
862e5b6d6dSopenharmony_ci| `U_USER_ATOMICS_H` | Set to the name of the low level atomics header file.   |
872e5b6d6dSopenharmony_ci| `U_USER_MUTEX_H`   | Mutexes header file.                                    |
882e5b6d6dSopenharmony_ci| `U_USER_MUTEX_CPP` | Mutexes and `InitOnce` implementation file.             |
892e5b6d6dSopenharmony_ci
902e5b6d6dSopenharmony_ciIt is possible (and reasonable) to supply only the two mutex files, while
912e5b6d6dSopenharmony_ciretaining the ICU default implementation for the low level atomics.
922e5b6d6dSopenharmony_ci
932e5b6d6dSopenharmony_ciExample ICU configure with user mutexes specified:
942e5b6d6dSopenharmony_ci
952e5b6d6dSopenharmony_ci    CPPFLAGS='-DU_USER_ATOMICS_H=atomic_c11.h -DU_USER_MUTEX_H=mutex_c11.h -DU_USER_MUTEX_CPP=mutex_c11.cpp' ./runConfigureICU --enable-debug Linux
962e5b6d6dSopenharmony_ci
972e5b6d6dSopenharmony_ci**Stability**
982e5b6d6dSopenharmony_ci
992e5b6d6dSopenharmony_ciThis interface may change between ICU releases. The required set of functions
1002e5b6d6dSopenharmony_cimay be extended, or details of the behavior required may be altered.
1012e5b6d6dSopenharmony_ci
1022e5b6d6dSopenharmony_ciThe types and functions defined by this interface reach deeply into the ICU
1032e5b6d6dSopenharmony_ciimplementation, and we need to retain the ability to make changes should the
1042e5b6d6dSopenharmony_cineed arise.
1052e5b6d6dSopenharmony_ci
1062e5b6d6dSopenharmony_ci**Examples**
1072e5b6d6dSopenharmony_ci
1082e5b6d6dSopenharmony_ciThe code below shows a complete set of ICU user synchronization files.
1092e5b6d6dSopenharmony_ci
1102e5b6d6dSopenharmony_ciThis implementation uses C++11 language mutexes and atomics. These make for a
1112e5b6d6dSopenharmony_ciconvenient reference implementation because the C++11 constructs are well
1122e5b6d6dSopenharmony_cidefined and straight forward to use.
1132e5b6d6dSopenharmony_ci
1142e5b6d6dSopenharmony_ciSimilar implementations for POSIX and Windows can be found in files
1152e5b6d6dSopenharmony_ci`common/umutex.h` and `common/umutex.cpp`, in the platform `#ifdef` chains; these are
1162e5b6d6dSopenharmony_cipart of the standard ICU distribution.
1172e5b6d6dSopenharmony_ci
1182e5b6d6dSopenharmony_ci**Mutex Header**
1192e5b6d6dSopenharmony_ci```c++
1202e5b6d6dSopenharmony_ci// Example of an ICU build time customized mutex header.
1212e5b6d6dSopenharmony_ci//
1222e5b6d6dSopenharmony_ci// Must define struct UMutex and an initializer that will work with static instances.
1232e5b6d6dSopenharmony_ci// All UMutex instances in ICU code will be static.
1242e5b6d6dSopenharmony_ci
1252e5b6d6dSopenharmony_ci#ifndef ICU_MUTEX_C11_H
1262e5b6d6dSopenharmony_ci#define ICU_MUTEX_C11_H
1272e5b6d6dSopenharmony_ci#include <mutex>
1282e5b6d6dSopenharmony_ci#include <condition_variable>
1292e5b6d6dSopenharmony_cistruct UMutex {
1302e5b6d6dSopenharmony_ci    std::mutex fMutex;
1312e5b6d6dSopenharmony_ci};
1322e5b6d6dSopenharmony_ci#define U_MUTEX_INITIALIZER {}
1332e5b6d6dSopenharmony_ci#endif
1342e5b6d6dSopenharmony_ci```
1352e5b6d6dSopenharmony_ci
1362e5b6d6dSopenharmony_ci**Atomics Header**
1372e5b6d6dSopenharmony_ci```c++
1382e5b6d6dSopenharmony_ci#include <atomic>
1392e5b6d6dSopenharmony_ci
1402e5b6d6dSopenharmony_citypedef std::atomic<int32_t> u_atomic_int32_t;
1412e5b6d6dSopenharmony_ci#define ATOMIC_INT32_T_INITIALIZER(val) ATOMIC_VAR_INIT(val)
1422e5b6d6dSopenharmony_ci
1432e5b6d6dSopenharmony_ciinline int32_t umtx_loadAcquire(u_atomic_int32_t &var) {
1442e5b6d6dSopenharmony_ci    return var.load(std::memory_order_acquire);
1452e5b6d6dSopenharmony_ci}
1462e5b6d6dSopenharmony_ci
1472e5b6d6dSopenharmony_ciinline void umtx_storeRelease(u_atomic_int32_t &var, int32_t val) {
1482e5b6d6dSopenharmony_ci    var.store(val, std::memory_order_release);
1492e5b6d6dSopenharmony_ci}
1502e5b6d6dSopenharmony_ci
1512e5b6d6dSopenharmony_ciinline int32_t umtx_atomic_inc(u_atomic_int32_t &var) {
1522e5b6d6dSopenharmony_ci    return var.fetch_add(1) + 1;
1532e5b6d6dSopenharmony_ci}
1542e5b6d6dSopenharmony_ci
1552e5b6d6dSopenharmony_ciinline int32_t umtx_atomic_dec(u_atomic_int32_t &var) {
1562e5b6d6dSopenharmony_ci    return var.fetch_sub(1) - 1;
1572e5b6d6dSopenharmony_ci}
1582e5b6d6dSopenharmony_ci```
1592e5b6d6dSopenharmony_ci
1602e5b6d6dSopenharmony_ci**Mutex and InitOnce implementations**
1612e5b6d6dSopenharmony_ci```c++
1622e5b6d6dSopenharmony_ci//
1632e5b6d6dSopenharmony_ci// Example ICU build time custom mutex cpp file.
1642e5b6d6dSopenharmony_ci//
1652e5b6d6dSopenharmony_ci// Must implement these functions:
1662e5b6d6dSopenharmony_ci// umtx_lock(UMutex *mutex);
1672e5b6d6dSopenharmony_ci// umtx_unlock(UMutex *mutex);
1682e5b6d6dSopenharmony_ci// umtx_initImplPreInit(UInitOnce &uio);
1692e5b6d6dSopenharmony_ci// umtx_initImplPostInit(UInitOnce &uio);
1702e5b6d6dSopenharmony_ci
1712e5b6d6dSopenharmony_ciU_CAPI void U_EXPORT2
1722e5b6d6dSopenharmony_ciumtx_lock(UMutex *mutex) {
1732e5b6d6dSopenharmony_ci    if (mutex == NULL) {
1742e5b6d6dSopenharmony_ci        // Note: globalMutex is pre-defined in the platform-independent ICU code.
1752e5b6d6dSopenharmony_ci        mutex = &globalMutex;
1762e5b6d6dSopenharmony_ci    }
1772e5b6d6dSopenharmony_ci    mutex->fMutex.lock();
1782e5b6d6dSopenharmony_ci}
1792e5b6d6dSopenharmony_ci
1802e5b6d6dSopenharmony_ciU_CAPI void U_EXPORT2
1812e5b6d6dSopenharmony_ciumtx_unlock(UMutex* mutex) `{
1822e5b6d6dSopenharmony_ci    if (mutex == NULL) {
1832e5b6d6dSopenharmony_ci        mutex = &globalMutex;
1842e5b6d6dSopenharmony_ci    }
1852e5b6d6dSopenharmony_ci    mutex->fMutex.unlock();
1862e5b6d6dSopenharmony_ci}
1872e5b6d6dSopenharmony_ci
1882e5b6d6dSopenharmony_ci// A mutex and a condition variable are used by the implementation of umtx_initOnce()
1892e5b6d6dSopenharmony_ci// The mutex is held only while the state of the InitOnce object is being changed or
1902e5b6d6dSopenharmony_ci// tested. It is not held while initialization functions are running.
1912e5b6d6dSopenharmony_ci// Threads needing to block, waiting for an initialization to complete, will wait
1922e5b6d6dSopenharmony_ci// on the condition variable.
1932e5b6d6dSopenharmony_ci// All InitOnce objects share a common mutex and condition variable. This means that
1942e5b6d6dSopenharmony_ci// all blocked threads will wake if any (possibly unrelated) initialization completes.
1952e5b6d6dSopenharmony_ci// Which does no harm, it should be statistically rare, and any spuriously woken
1962e5b6d6dSopenharmony_ci// threads will check their state and promptly wait again.
1972e5b6d6dSopenharmony_ci
1982e5b6d6dSopenharmony_cistatic std::mutex initMutex;
1992e5b6d6dSopenharmony_cistatic std::condition_variable initCondition;
2002e5b6d6dSopenharmony_ci
2012e5b6d6dSopenharmony_ci// This function is called from umtx_initOnce() when an initial test of a UInitOnce::fState flag
2022e5b6d6dSopenharmony_ci// reveals that initialization has not completed, that we either need to call the
2032e5b6d6dSopenharmony_ci// function on this thread, or wait for some other thread to complete the initialization.
2042e5b6d6dSopenharmony_ci//
2052e5b6d6dSopenharmony_ci// The actual call to the init function is made inline by template code
2062e5b6d6dSopenharmony_ci// that knows the C++ types involved. This function returns true if
2072e5b6d6dSopenharmony_ci// the inline code needs to invoke the Init function, or false if the initialization
2082e5b6d6dSopenharmony_ci// has completed on another thread.
2092e5b6d6dSopenharmony_ci//
2102e5b6d6dSopenharmony_ci// UInitOnce::fState values:
2112e5b6d6dSopenharmony_ci// 0: Initialization has not yet begun.
2122e5b6d6dSopenharmony_ci// 1: Initialization is in progress, not yet complete.
2132e5b6d6dSopenharmony_ci// 2: Initialization is complete.
2142e5b6d6dSopenharmony_ci//
2152e5b6d6dSopenharmony_ciUBool umtx_initImplPreInit(UInitOnce &uio) {
2162e5b6d6dSopenharmony_ci    std::unique_lock<std::mutex> initLock(initMutex);
2172e5b6d6dSopenharmony_ci    int32_t state = uio.fState;
2182e5b6d6dSopenharmony_ci    if (state == 0) {
2192e5b6d6dSopenharmony_ci        umtx_storeRelease(uio.fState, 1);
2202e5b6d6dSopenharmony_ci        return true; // Caller will next call the init function.
2212e5b6d6dSopenharmony_ci    } else {
2222e5b6d6dSopenharmony_ci        while (uio.fState == 1) {
2232e5b6d6dSopenharmony_ci            // Another thread is currently running the initialization.
2242e5b6d6dSopenharmony_ci            // Wait until it completes.
2252e5b6d6dSopenharmony_ci            initCondition.wait(initLock);
2262e5b6d6dSopenharmony_ci        }
2272e5b6d6dSopenharmony_ci        U_ASSERT(uio.fState == 2);
2282e5b6d6dSopenharmony_ci        return false;
2292e5b6d6dSopenharmony_ci    }
2302e5b6d6dSopenharmony_ci}
2312e5b6d6dSopenharmony_ci
2322e5b6d6dSopenharmony_ci// This function is called from umtx_initOnce() just after an initializationfunction completes.
2332e5b6d6dSopenharmony_ci// Its purpose is to set the state of the UInitOnce object to initialized, and to
2342e5b6d6dSopenharmony_ci// unblock any threads that may be waiting on the initialization.
2352e5b6d6dSopenharmony_ci//
2362e5b6d6dSopenharmony_ci// Some threads may be waiting on the condition variable, requiring the notify_all().
2372e5b6d6dSopenharmony_ci// Some threads may be racing to test the fState flag outside of the mutex, 
2382e5b6d6dSopenharmony_ci// requiring the use of store-release when changing its value.
2392e5b6d6dSopenharmony_ci
2402e5b6d6dSopenharmony_civoid umtx_initImplPostInit(UInitOnce &uio) {
2412e5b6d6dSopenharmony_ci    std::unique_lock<std::mutex> initLock(initMutex);
2422e5b6d6dSopenharmony_ci    umtx_storeRelease(uio.fState, 2);
2432e5b6d6dSopenharmony_ci    initCondition.notify_all();
2442e5b6d6dSopenharmony_ci}
2452e5b6d6dSopenharmony_ci```
246