]> git.saurik.com Git - apple/icu.git/blob - icuSources/common/umutex.cpp
ICU-64232.0.1.tar.gz
[apple/icu.git] / icuSources / common / umutex.cpp
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 "cmemory.h"
28
29 U_NAMESPACE_BEGIN
30
31
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
36 #endif
37
38 /*************************************************************************************************
39 *
40 * ICU Mutex wrappers.
41 *
42 *************************************************************************************************/
43
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);
47 return m;
48 }
49
50 U_CAPI void U_EXPORT2
51 umtx_lock(UMutex *mutex) {
52 if (mutex == nullptr) {
53 mutex = globalMutex();
54 }
55 mutex->fMutex.lock();
56 }
57
58
59 U_CAPI void U_EXPORT2
60 umtx_unlock(UMutex* mutex)
61 {
62 if (mutex == nullptr) {
63 mutex = globalMutex();
64 }
65 mutex->fMutex.unlock();
66 }
67
68
69 /*************************************************************************************************
70 *
71 * UInitOnce Implementation
72 *
73 *************************************************************************************************/
74
75 static std::mutex &initMutex() {
76 static std::mutex *m = STATIC_NEW(std::mutex);
77 return *m;
78 }
79
80 static std::condition_variable &initCondition() {
81 static std::condition_variable *cv = STATIC_NEW(std::condition_variable);
82 return *cv;
83 }
84
85
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.
89 //
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.
93 //
94 U_COMMON_API UBool U_EXPORT2
95 umtx_initImplPreInit(UInitOnce &uio) {
96 std::unique_lock<std::mutex> lock(initMutex());
97
98 if (umtx_loadAcquire(uio.fState) == 0) {
99 umtx_storeRelease(uio.fState, 1);
100 return true; // Caller will next call the init function.
101 } else {
102 while (umtx_loadAcquire(uio.fState) == 1) {
103 // Another thread is currently running the initialization.
104 // Wait until it completes.
105 initCondition().wait(lock);
106 }
107 U_ASSERT(uio.fState == 2);
108 return false;
109 }
110 }
111
112
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.
118
119 U_COMMON_API void U_EXPORT2
120 umtx_initImplPostInit(UInitOnce &uio) {
121 {
122 std::unique_lock<std::mutex> lock(initMutex());
123 umtx_storeRelease(uio.fState, 2);
124 }
125 initCondition().notify_all();
126 }
127
128 U_NAMESPACE_END
129
130 /*************************************************************************************************
131 *
132 * Deprecated functions for setting user mutexes.
133 *
134 *************************************************************************************************/
135
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;
141 }
142 return;
143 }
144
145
146
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;
152 }
153 return;
154 }