]>
Commit | Line | Data |
---|---|---|
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" | |
57a6839d | 27 | #include "cmemory.h" |
51004dcb | 28 | |
3d1f044b | 29 | U_NAMESPACE_BEGIN |
57a6839d | 30 | |
51004dcb | 31 | |
57a6839d | 32 | #if defined(U_USER_MUTEX_CPP) |
3d1f044b A |
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 | |
51004dcb A |
36 | #endif |
37 | ||
3d1f044b A |
38 | /************************************************************************************************* |
39 | * | |
40 | * ICU Mutex wrappers. | |
41 | * | |
42 | *************************************************************************************************/ | |
51004dcb | 43 | |
3d1f044b A |
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; | |
b331163b A |
48 | } |
49 | ||
51004dcb A |
50 | U_CAPI void U_EXPORT2 |
51 | umtx_lock(UMutex *mutex) { | |
3d1f044b A |
52 | if (mutex == nullptr) { |
53 | mutex = globalMutex(); | |
51004dcb | 54 | } |
3d1f044b | 55 | mutex->fMutex.lock(); |
51004dcb A |
56 | } |
57 | ||
57a6839d | 58 | |
51004dcb A |
59 | U_CAPI void U_EXPORT2 |
60 | umtx_unlock(UMutex* mutex) | |
61 | { | |
3d1f044b A |
62 | if (mutex == nullptr) { |
63 | mutex = globalMutex(); | |
51004dcb | 64 | } |
3d1f044b | 65 | mutex->fMutex.unlock(); |
51004dcb A |
66 | } |
67 | ||
b331163b | 68 | |
3d1f044b A |
69 | /************************************************************************************************* |
70 | * | |
71 | * UInitOnce Implementation | |
72 | * | |
73 | *************************************************************************************************/ | |
b331163b | 74 | |
3d1f044b A |
75 | static std::mutex &initMutex() { |
76 | static std::mutex *m = STATIC_NEW(std::mutex); | |
77 | return *m; | |
b331163b A |
78 | } |
79 | ||
3d1f044b A |
80 | static std::condition_variable &initCondition() { |
81 | static std::condition_variable *cv = STATIC_NEW(std::condition_variable); | |
82 | return *cv; | |
b331163b A |
83 | } |
84 | ||
85 | ||
57a6839d | 86 | // This function is called when a test of a UInitOnce::fState reveals that |
3d1f044b | 87 | // initialization has not completed, that we either need to call the init |
57a6839d A |
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 | |
3d1f044b | 91 | // that knows the C++ types involved. This function returns true if |
57a6839d A |
92 | // the caller needs to call the Init function. |
93 | // | |
94 | U_COMMON_API UBool U_EXPORT2 | |
95 | umtx_initImplPreInit(UInitOnce &uio) { | |
3d1f044b A |
96 | std::unique_lock<std::mutex> lock(initMutex()); |
97 | ||
98 | if (umtx_loadAcquire(uio.fState) == 0) { | |
57a6839d | 99 | umtx_storeRelease(uio.fState, 1); |
3d1f044b | 100 | return true; // Caller will next call the init function. |
57a6839d | 101 | } else { |
3d1f044b | 102 | while (umtx_loadAcquire(uio.fState) == 1) { |
57a6839d A |
103 | // Another thread is currently running the initialization. |
104 | // Wait until it completes. | |
3d1f044b | 105 | initCondition().wait(lock); |
57a6839d | 106 | } |
57a6839d | 107 | U_ASSERT(uio.fState == 2); |
3d1f044b | 108 | return false; |
51004dcb | 109 | } |
57a6839d | 110 | } |
51004dcb | 111 | |
51004dcb | 112 | |
57a6839d A |
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) { | |
3d1f044b A |
121 | { |
122 | std::unique_lock<std::mutex> lock(initMutex()); | |
123 | umtx_storeRelease(uio.fState, 2); | |
124 | } | |
125 | initCondition().notify_all(); | |
57a6839d | 126 | } |
51004dcb | 127 | |
57a6839d | 128 | U_NAMESPACE_END |
51004dcb | 129 | |
3d1f044b A |
130 | /************************************************************************************************* |
131 | * | |
132 | * Deprecated functions for setting user mutexes. | |
133 | * | |
134 | *************************************************************************************************/ | |
51004dcb | 135 | |
57a6839d A |
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; | |
51004dcb | 141 | } |
57a6839d | 142 | return; |
51004dcb A |
143 | } |
144 | ||
145 | ||
57a6839d A |
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; | |
51004dcb | 154 | } |