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"
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
40 /*************************************************************************************************
44 *************************************************************************************************/
47 std::mutex
*initMutex
;
48 std::condition_variable
*initCondition
;
50 // The ICU global mutex.
51 // Used when ICU implementation code passes nullptr for the mutex pointer.
54 std::once_flag initFlag
;
55 std::once_flag
*pInitFlag
= &initFlag
;
57 } // Anonymous namespace
60 static UBool U_CALLCONV
umtx_cleanup() {
62 initCondition
->~condition_variable();
65 // Reset the once_flag, by destructing it and creating a fresh one in its place.
66 // Do not use this trick anywhere else in ICU; use umtx_initOnce, not std::call_once().
67 pInitFlag
->~once_flag();
68 pInitFlag
= new(&initFlag
) std::once_flag();
72 static void U_CALLCONV
umtx_init() {
73 initMutex
= STATIC_NEW(std::mutex
);
74 initCondition
= STATIC_NEW(std::condition_variable
);
75 ucln_common_registerCleanup(UCLN_COMMON_MUTEX
, umtx_cleanup
);
80 std::mutex
*UMutex::getMutex() {
81 std::mutex
*retPtr
= fMutex
.load(std::memory_order_acquire
);
82 if (retPtr
== nullptr) {
83 std::call_once(*pInitFlag
, umtx_init
);
84 std::lock_guard
<std::mutex
> guard(*initMutex
);
85 retPtr
= fMutex
.load(std::memory_order_acquire
);
86 if (retPtr
== nullptr) {
87 fMutex
= new(fStorage
) std::mutex();
89 fListLink
= gListHead
;
93 U_ASSERT(retPtr
!= nullptr);
97 UMutex
*UMutex::gListHead
= nullptr;
99 void UMutex::cleanup() {
100 UMutex
*next
= nullptr;
101 for (UMutex
*m
= gListHead
; m
!= nullptr; m
= next
) {
102 (*m
->fMutex
).~mutex();
105 m
->fListLink
= nullptr;
111 U_CAPI
void U_EXPORT2
112 umtx_lock(UMutex
*mutex
) {
113 if (mutex
== nullptr) {
114 mutex
= &globalMutex
;
120 U_CAPI
void U_EXPORT2
121 umtx_unlock(UMutex
* mutex
)
123 if (mutex
== nullptr) {
124 mutex
= &globalMutex
;
130 /*************************************************************************************************
132 * UInitOnce Implementation
134 *************************************************************************************************/
136 // This function is called when a test of a UInitOnce::fState reveals that
137 // initialization has not completed, that we either need to call the init
138 // function on this thread, or wait for some other thread to complete.
140 // The actual call to the init function is made inline by template code
141 // that knows the C++ types involved. This function returns true if
142 // the caller needs to call the Init function.
144 U_COMMON_API UBool U_EXPORT2
145 umtx_initImplPreInit(UInitOnce
&uio
) {
146 std::call_once(*pInitFlag
, umtx_init
);
147 std::unique_lock
<std::mutex
> lock(*initMutex
);
148 if (umtx_loadAcquire(uio
.fState
) == 0) {
149 umtx_storeRelease(uio
.fState
, 1);
150 return true; // Caller will next call the init function.
152 while (umtx_loadAcquire(uio
.fState
) == 1) {
153 // Another thread is currently running the initialization.
154 // Wait until it completes.
155 initCondition
->wait(lock
);
157 U_ASSERT(uio
.fState
== 2);
163 // This function is called by the thread that ran an initialization function,
164 // just after completing the function.
165 // Some threads may be waiting on the condition, requiring the broadcast wakeup.
166 // Some threads may be racing to test the fState variable outside of the mutex,
167 // requiring the use of store/release when changing its value.
169 U_COMMON_API
void U_EXPORT2
170 umtx_initImplPostInit(UInitOnce
&uio
) {
172 std::unique_lock
<std::mutex
> lock(*initMutex
);
173 umtx_storeRelease(uio
.fState
, 2);
175 initCondition
->notify_all();
180 /*************************************************************************************************
182 * Deprecated functions for setting user mutexes.
184 *************************************************************************************************/
186 U_DEPRECATED
void U_EXPORT2
187 u_setMutexFunctions(const void * /*context */, UMtxInitFn
*, UMtxFn
*,
188 UMtxFn
*, UMtxFn
*, UErrorCode
*status
) {
189 if (U_SUCCESS(*status
)) {
190 *status
= U_UNSUPPORTED_ERROR
;
197 U_DEPRECATED
void U_EXPORT2
198 u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn
*, UMtxAtomicFn
*,
199 UErrorCode
*status
) {
200 if (U_SUCCESS(*status
)) {
201 *status
= U_UNSUPPORTED_ERROR
;