]> git.saurik.com Git - apple/icu.git/blame - icuSources/common/umutex.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / common / umutex.cpp
CommitLineData
f3c0d7a5
A
1// © 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
51004dcb
A
3/*
4******************************************************************************
5*
f3c0d7a5 6* Copyright (C) 1997-2016, International Business Machines
51004dcb
A
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
57a6839d
A
23#include "umutex.h"
24
51004dcb
A
25#include "unicode/utypes.h"
26#include "uassert.h"
340931cb 27#include "ucln_cmn.h"
57a6839d 28#include "cmemory.h"
51004dcb 29
3d1f044b 30U_NAMESPACE_BEGIN
57a6839d 31
51004dcb 32
57a6839d 33#if defined(U_USER_MUTEX_CPP)
3d1f044b
A
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
51004dcb
A
37#endif
38
340931cb 39
3d1f044b
A
40/*************************************************************************************************
41 *
42 * ICU Mutex wrappers.
43 *
44 *************************************************************************************************/
51004dcb 45
340931cb
A
46namespace {
47std::mutex *initMutex;
48std::condition_variable *initCondition;
49
50// The ICU global mutex.
51// Used when ICU implementation code passes nullptr for the mutex pointer.
52UMutex globalMutex;
53
54std::once_flag initFlag;
55std::once_flag *pInitFlag = &initFlag;
56
57} // Anonymous namespace
58
59U_CDECL_BEGIN
60static UBool U_CALLCONV umtx_cleanup() {
61 initMutex->~mutex();
62 initCondition->~condition_variable();
63 UMutex::cleanup();
64
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();
69 return true;
70}
71
72static 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);
76}
77U_CDECL_END
78
79
80std::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();
88 retPtr = fMutex;
89 fListLink = gListHead;
90 gListHead = this;
91 }
92 }
93 U_ASSERT(retPtr != nullptr);
94 return retPtr;
95}
96
97UMutex *UMutex::gListHead = nullptr;
98
99void UMutex::cleanup() {
100 UMutex *next = nullptr;
101 for (UMutex *m = gListHead; m != nullptr; m = next) {
102 (*m->fMutex).~mutex();
103 m->fMutex = nullptr;
104 next = m->fListLink;
105 m->fListLink = nullptr;
106 }
107 gListHead = nullptr;
b331163b
A
108}
109
340931cb 110
51004dcb
A
111U_CAPI void U_EXPORT2
112umtx_lock(UMutex *mutex) {
3d1f044b 113 if (mutex == nullptr) {
340931cb 114 mutex = &globalMutex;
51004dcb 115 }
340931cb 116 mutex->lock();
51004dcb
A
117}
118
57a6839d 119
51004dcb
A
120U_CAPI void U_EXPORT2
121umtx_unlock(UMutex* mutex)
122{
3d1f044b 123 if (mutex == nullptr) {
340931cb 124 mutex = &globalMutex;
51004dcb 125 }
340931cb 126 mutex->unlock();
51004dcb
A
127}
128
b331163b 129
3d1f044b
A
130/*************************************************************************************************
131 *
132 * UInitOnce Implementation
133 *
134 *************************************************************************************************/
b331163b 135
57a6839d 136// This function is called when a test of a UInitOnce::fState reveals that
3d1f044b 137// initialization has not completed, that we either need to call the init
57a6839d
A
138// function on this thread, or wait for some other thread to complete.
139//
140// The actual call to the init function is made inline by template code
3d1f044b 141// that knows the C++ types involved. This function returns true if
57a6839d
A
142// the caller needs to call the Init function.
143//
144U_COMMON_API UBool U_EXPORT2
145umtx_initImplPreInit(UInitOnce &uio) {
340931cb
A
146 std::call_once(*pInitFlag, umtx_init);
147 std::unique_lock<std::mutex> lock(*initMutex);
3d1f044b 148 if (umtx_loadAcquire(uio.fState) == 0) {
57a6839d 149 umtx_storeRelease(uio.fState, 1);
3d1f044b 150 return true; // Caller will next call the init function.
57a6839d 151 } else {
3d1f044b 152 while (umtx_loadAcquire(uio.fState) == 1) {
57a6839d
A
153 // Another thread is currently running the initialization.
154 // Wait until it completes.
340931cb 155 initCondition->wait(lock);
57a6839d 156 }
57a6839d 157 U_ASSERT(uio.fState == 2);
3d1f044b 158 return false;
51004dcb 159 }
57a6839d 160}
51004dcb 161
51004dcb 162
57a6839d
A
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.
168
169U_COMMON_API void U_EXPORT2
170umtx_initImplPostInit(UInitOnce &uio) {
3d1f044b 171 {
340931cb 172 std::unique_lock<std::mutex> lock(*initMutex);
3d1f044b
A
173 umtx_storeRelease(uio.fState, 2);
174 }
340931cb 175 initCondition->notify_all();
57a6839d 176}
51004dcb 177
57a6839d 178U_NAMESPACE_END
51004dcb 179
3d1f044b
A
180/*************************************************************************************************
181 *
182 * Deprecated functions for setting user mutexes.
183 *
184 *************************************************************************************************/
51004dcb 185
57a6839d
A
186U_DEPRECATED void U_EXPORT2
187u_setMutexFunctions(const void * /*context */, UMtxInitFn *, UMtxFn *,
188 UMtxFn *, UMtxFn *, UErrorCode *status) {
189 if (U_SUCCESS(*status)) {
190 *status = U_UNSUPPORTED_ERROR;
51004dcb 191 }
57a6839d 192 return;
51004dcb
A
193}
194
195
57a6839d
A
196
197U_DEPRECATED void U_EXPORT2
198u_setAtomicIncDecFunctions(const void * /*context */, UMtxAtomicFn *, UMtxAtomicFn *,
199 UErrorCode *status) {
200 if (U_SUCCESS(*status)) {
201 *status = U_UNSUPPORTED_ERROR;
202 }
203 return;
51004dcb 204}