1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 ******************************************************************************
13 * Modification History:
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 ******************************************************************************
25 #include "unicode/utypes.h"
32 #if defined(U_USER_MUTEX_CPP)
33 // Support for including an alternate implementation of mutexes has been withdrawn.
34 // See issue ICU-20185.
35 #error U_USER_MUTEX_CPP not supported
38 /*************************************************************************************************
42 *************************************************************************************************/
44 // The ICU global mutex. Used when ICU implementation code passes NULL for the mutex pointer.
45 static UMutex
*globalMutex() {
46 static UMutex
*m
= STATIC_NEW(UMutex
);
51 umtx_lock(UMutex
*mutex
) {
52 if (mutex
== nullptr) {
53 mutex
= globalMutex();
60 umtx_unlock(UMutex
* mutex
)
62 if (mutex
== nullptr) {
63 mutex
= globalMutex();
65 mutex
->fMutex
.unlock();
69 /*************************************************************************************************
71 * UInitOnce Implementation
73 *************************************************************************************************/
75 static std::mutex
&initMutex() {
76 static std::mutex
*m
= STATIC_NEW(std::mutex
);
80 static std::condition_variable
&initCondition() {
81 static std::condition_variable
*cv
= STATIC_NEW(std::condition_variable
);
86 // This function is called when a test of a UInitOnce::fState reveals that
87 // initialization has not completed, that we either need to call the init
88 // function on this thread, or wait for some other thread to complete.
90 // The actual call to the init function is made inline by template code
91 // that knows the C++ types involved. This function returns true if
92 // the caller needs to call the Init function.
94 U_COMMON_API UBool U_EXPORT2
95 umtx_initImplPreInit(UInitOnce
&uio
) {
96 std::unique_lock
<std::mutex
> lock(initMutex());
98 if (umtx_loadAcquire(uio
.fState
) == 0) {
99 umtx_storeRelease(uio
.fState
, 1);
100 return true; // Caller will next call the init function.
102 while (umtx_loadAcquire(uio
.fState
) == 1) {
103 // Another thread is currently running the initialization.
104 // Wait until it completes.
105 initCondition().wait(lock
);
107 U_ASSERT(uio
.fState
== 2);
113 // This function is called by the thread that ran an initialization function,
114 // just after completing the function.
115 // Some threads may be waiting on the condition, requiring the broadcast wakeup.
116 // Some threads may be racing to test the fState variable outside of the mutex,
117 // requiring the use of store/release when changing its value.
119 U_COMMON_API
void U_EXPORT2
120 umtx_initImplPostInit(UInitOnce
&uio
) {
122 std::unique_lock
<std::mutex
> lock(initMutex());
123 umtx_storeRelease(uio
.fState
, 2);
125 initCondition().notify_all();
130 /*************************************************************************************************
132 * Deprecated functions for setting user mutexes.
134 *************************************************************************************************/
136 U_DEPRECATED
void U_EXPORT2
137 u_setMutexFunctions(const void * /*context */, UMtxInitFn
*, UMtxFn
*,
138 UMtxFn
*, UMtxFn
*, UErrorCode
*status
) {
139 if (U_SUCCESS(*status
)) {
140 *status
= U_UNSUPPORTED_ERROR
;
147 U_DEPRECATED
void U_EXPORT2
148 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn
*, UMtxAtomicFn
*,
149 UErrorCode
*status
) {
150 if (U_SUCCESS(*status
)) {
151 *status
= U_UNSUPPORTED_ERROR
;