]>
Commit | Line | Data |
---|---|---|
be8de894 JW |
1 | // shared_ptr atomic access -*- C++ -*- |
2 | ||
a5544970 | 3 | // Copyright (C) 2014-2019 Free Software Foundation, Inc. |
be8de894 JW |
4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file bits/shared_ptr_atomic.h | |
26 | * This is an internal header file, included by other library headers. | |
27 | * Do not attempt to use it directly. @headername{memory} | |
28 | */ | |
29 | ||
30 | #ifndef _SHARED_PTR_ATOMIC_H | |
31 | #define _SHARED_PTR_ATOMIC_H 1 | |
32 | ||
33 | #include <bits/atomic_base.h> | |
34 | ||
35 | namespace std _GLIBCXX_VISIBILITY(default) | |
36 | { | |
37 | _GLIBCXX_BEGIN_NAMESPACE_VERSION | |
38 | ||
39 | /** | |
40 | * @addtogroup pointer_abstractions | |
41 | * @{ | |
42 | */ | |
43 | ||
44 | struct _Sp_locker | |
45 | { | |
46 | _Sp_locker(const _Sp_locker&) = delete; | |
47 | _Sp_locker& operator=(const _Sp_locker&) = delete; | |
48 | ||
49 | #ifdef __GTHREADS | |
50 | explicit | |
51 | _Sp_locker(const void*) noexcept; | |
52 | _Sp_locker(const void*, const void*) noexcept; | |
53 | ~_Sp_locker(); | |
54 | ||
55 | private: | |
56 | unsigned char _M_key1; | |
57 | unsigned char _M_key2; | |
58 | #else | |
59 | explicit _Sp_locker(const void*, const void* = nullptr) { } | |
60 | #endif | |
61 | }; | |
62 | ||
63 | /** | |
64 | * @brief Report whether shared_ptr atomic operations are lock-free. | |
65 | * @param __p A non-null pointer to a shared_ptr object. | |
66 | * @return True if atomic access to @c *__p is lock-free, false otherwise. | |
67 | * @{ | |
68 | */ | |
69 | template<typename _Tp, _Lock_policy _Lp> | |
70 | inline bool | |
71 | atomic_is_lock_free(const __shared_ptr<_Tp, _Lp>* __p) | |
72 | { | |
73 | #ifdef __GTHREADS | |
74 | return __gthread_active_p() == 0; | |
75 | #else | |
76 | return true; | |
77 | #endif | |
78 | } | |
79 | ||
80 | template<typename _Tp> | |
81 | inline bool | |
82 | atomic_is_lock_free(const shared_ptr<_Tp>* __p) | |
83 | { return std::atomic_is_lock_free<_Tp, __default_lock_policy>(__p); } | |
84 | ||
85 | // @} | |
86 | ||
87 | /** | |
88 | * @brief Atomic load for shared_ptr objects. | |
89 | * @param __p A non-null pointer to a shared_ptr object. | |
90 | * @return @c *__p | |
91 | * | |
92 | * The memory order shall not be @c memory_order_release or | |
93 | * @c memory_order_acq_rel. | |
94 | * @{ | |
95 | */ | |
96 | template<typename _Tp> | |
97 | inline shared_ptr<_Tp> | |
98 | atomic_load_explicit(const shared_ptr<_Tp>* __p, memory_order) | |
99 | { | |
100 | _Sp_locker __lock{__p}; | |
101 | return *__p; | |
102 | } | |
103 | ||
104 | template<typename _Tp> | |
105 | inline shared_ptr<_Tp> | |
106 | atomic_load(const shared_ptr<_Tp>* __p) | |
107 | { return std::atomic_load_explicit(__p, memory_order_seq_cst); } | |
108 | ||
109 | template<typename _Tp, _Lock_policy _Lp> | |
110 | inline __shared_ptr<_Tp, _Lp> | |
111 | atomic_load_explicit(const __shared_ptr<_Tp, _Lp>* __p, memory_order) | |
112 | { | |
113 | _Sp_locker __lock{__p}; | |
114 | return *__p; | |
115 | } | |
116 | ||
117 | template<typename _Tp, _Lock_policy _Lp> | |
118 | inline __shared_ptr<_Tp, _Lp> | |
119 | atomic_load(const __shared_ptr<_Tp, _Lp>* __p) | |
120 | { return std::atomic_load_explicit(__p, memory_order_seq_cst); } | |
121 | // @} | |
122 | ||
123 | /** | |
124 | * @brief Atomic store for shared_ptr objects. | |
125 | * @param __p A non-null pointer to a shared_ptr object. | |
126 | * @param __r The value to store. | |
127 | * | |
128 | * The memory order shall not be @c memory_order_acquire or | |
129 | * @c memory_order_acq_rel. | |
130 | * @{ | |
131 | */ | |
132 | template<typename _Tp> | |
133 | inline void | |
134 | atomic_store_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, | |
135 | memory_order) | |
136 | { | |
137 | _Sp_locker __lock{__p}; | |
138 | __p->swap(__r); // use swap so that **__p not destroyed while lock held | |
139 | } | |
140 | ||
141 | template<typename _Tp> | |
142 | inline void | |
143 | atomic_store(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) | |
144 | { std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); } | |
145 | ||
146 | template<typename _Tp, _Lock_policy _Lp> | |
147 | inline void | |
148 | atomic_store_explicit(__shared_ptr<_Tp, _Lp>* __p, | |
149 | __shared_ptr<_Tp, _Lp> __r, | |
150 | memory_order) | |
151 | { | |
152 | _Sp_locker __lock{__p}; | |
153 | __p->swap(__r); // use swap so that **__p not destroyed while lock held | |
154 | } | |
155 | ||
156 | template<typename _Tp, _Lock_policy _Lp> | |
157 | inline void | |
158 | atomic_store(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r) | |
159 | { std::atomic_store_explicit(__p, std::move(__r), memory_order_seq_cst); } | |
160 | // @} | |
161 | ||
162 | /** | |
163 | * @brief Atomic exchange for shared_ptr objects. | |
164 | * @param __p A non-null pointer to a shared_ptr object. | |
165 | * @param __r New value to store in @c *__p. | |
166 | * @return The original value of @c *__p | |
167 | * @{ | |
168 | */ | |
169 | template<typename _Tp> | |
170 | inline shared_ptr<_Tp> | |
171 | atomic_exchange_explicit(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r, | |
172 | memory_order) | |
173 | { | |
174 | _Sp_locker __lock{__p}; | |
175 | __p->swap(__r); | |
176 | return __r; | |
177 | } | |
178 | ||
179 | template<typename _Tp> | |
180 | inline shared_ptr<_Tp> | |
181 | atomic_exchange(shared_ptr<_Tp>* __p, shared_ptr<_Tp> __r) | |
182 | { | |
183 | return std::atomic_exchange_explicit(__p, std::move(__r), | |
184 | memory_order_seq_cst); | |
185 | } | |
186 | ||
187 | template<typename _Tp, _Lock_policy _Lp> | |
188 | inline __shared_ptr<_Tp, _Lp> | |
189 | atomic_exchange_explicit(__shared_ptr<_Tp, _Lp>* __p, | |
190 | __shared_ptr<_Tp, _Lp> __r, | |
191 | memory_order) | |
192 | { | |
193 | _Sp_locker __lock{__p}; | |
194 | __p->swap(__r); | |
195 | return __r; | |
196 | } | |
197 | ||
198 | template<typename _Tp, _Lock_policy _Lp> | |
199 | inline __shared_ptr<_Tp, _Lp> | |
200 | atomic_exchange(__shared_ptr<_Tp, _Lp>* __p, __shared_ptr<_Tp, _Lp> __r) | |
201 | { | |
202 | return std::atomic_exchange_explicit(__p, std::move(__r), | |
203 | memory_order_seq_cst); | |
204 | } | |
205 | // @} | |
206 | ||
207 | /** | |
208 | * @brief Atomic compare-and-swap for shared_ptr objects. | |
209 | * @param __p A non-null pointer to a shared_ptr object. | |
210 | * @param __v A non-null pointer to a shared_ptr object. | |
211 | * @param __w A non-null pointer to a shared_ptr object. | |
212 | * @return True if @c *__p was equivalent to @c *__v, false otherwise. | |
213 | * | |
214 | * The memory order for failure shall not be @c memory_order_release or | |
215 | * @c memory_order_acq_rel, or stronger than the memory order for success. | |
216 | * @{ | |
217 | */ | |
218 | template<typename _Tp> | |
219 | bool | |
220 | atomic_compare_exchange_strong_explicit(shared_ptr<_Tp>* __p, | |
221 | shared_ptr<_Tp>* __v, | |
222 | shared_ptr<_Tp> __w, | |
223 | memory_order, | |
224 | memory_order) | |
225 | { | |
226 | shared_ptr<_Tp> __x; // goes out of scope after __lock | |
227 | _Sp_locker __lock{__p, __v}; | |
228 | owner_less<shared_ptr<_Tp>> __less; | |
229 | if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p)) | |
230 | { | |
231 | __x = std::move(*__p); | |
232 | *__p = std::move(__w); | |
233 | return true; | |
234 | } | |
235 | __x = std::move(*__v); | |
236 | *__v = *__p; | |
237 | return false; | |
238 | } | |
239 | ||
240 | template<typename _Tp> | |
241 | inline bool | |
242 | atomic_compare_exchange_strong(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, | |
243 | shared_ptr<_Tp> __w) | |
244 | { | |
245 | return std::atomic_compare_exchange_strong_explicit(__p, __v, | |
246 | std::move(__w), memory_order_seq_cst, memory_order_seq_cst); | |
247 | } | |
248 | ||
249 | template<typename _Tp> | |
250 | inline bool | |
251 | atomic_compare_exchange_weak_explicit(shared_ptr<_Tp>* __p, | |
252 | shared_ptr<_Tp>* __v, | |
253 | shared_ptr<_Tp> __w, | |
254 | memory_order __success, | |
255 | memory_order __failure) | |
256 | { | |
257 | return std::atomic_compare_exchange_strong_explicit(__p, __v, | |
258 | std::move(__w), __success, __failure); | |
259 | } | |
260 | ||
261 | template<typename _Tp> | |
262 | inline bool | |
263 | atomic_compare_exchange_weak(shared_ptr<_Tp>* __p, shared_ptr<_Tp>* __v, | |
264 | shared_ptr<_Tp> __w) | |
265 | { | |
266 | return std::atomic_compare_exchange_weak_explicit(__p, __v, | |
267 | std::move(__w), memory_order_seq_cst, memory_order_seq_cst); | |
268 | } | |
269 | ||
270 | template<typename _Tp, _Lock_policy _Lp> | |
271 | bool | |
272 | atomic_compare_exchange_strong_explicit(__shared_ptr<_Tp, _Lp>* __p, | |
273 | __shared_ptr<_Tp, _Lp>* __v, | |
274 | __shared_ptr<_Tp, _Lp> __w, | |
275 | memory_order, | |
276 | memory_order) | |
277 | { | |
278 | __shared_ptr<_Tp, _Lp> __x; // goes out of scope after __lock | |
279 | _Sp_locker __lock{__p, __v}; | |
280 | owner_less<__shared_ptr<_Tp, _Lp>> __less; | |
281 | if (*__p == *__v && !__less(*__p, *__v) && !__less(*__v, *__p)) | |
282 | { | |
283 | __x = std::move(*__p); | |
284 | *__p = std::move(__w); | |
285 | return true; | |
286 | } | |
287 | __x = std::move(*__v); | |
288 | *__v = *__p; | |
289 | return false; | |
290 | } | |
291 | ||
292 | template<typename _Tp, _Lock_policy _Lp> | |
293 | inline bool | |
294 | atomic_compare_exchange_strong(__shared_ptr<_Tp, _Lp>* __p, | |
295 | __shared_ptr<_Tp, _Lp>* __v, | |
296 | __shared_ptr<_Tp, _Lp> __w) | |
297 | { | |
298 | return std::atomic_compare_exchange_strong_explicit(__p, __v, | |
299 | std::move(__w), memory_order_seq_cst, memory_order_seq_cst); | |
300 | } | |
301 | ||
302 | template<typename _Tp, _Lock_policy _Lp> | |
303 | inline bool | |
304 | atomic_compare_exchange_weak_explicit(__shared_ptr<_Tp, _Lp>* __p, | |
305 | __shared_ptr<_Tp, _Lp>* __v, | |
306 | __shared_ptr<_Tp, _Lp> __w, | |
307 | memory_order __success, | |
308 | memory_order __failure) | |
309 | { | |
310 | return std::atomic_compare_exchange_strong_explicit(__p, __v, | |
311 | std::move(__w), __success, __failure); | |
312 | } | |
313 | ||
314 | template<typename _Tp, _Lock_policy _Lp> | |
315 | inline bool | |
316 | atomic_compare_exchange_weak(__shared_ptr<_Tp, _Lp>* __p, | |
317 | __shared_ptr<_Tp, _Lp>* __v, | |
318 | __shared_ptr<_Tp, _Lp> __w) | |
319 | { | |
320 | return std::atomic_compare_exchange_weak_explicit(__p, __v, | |
321 | std::move(__w), memory_order_seq_cst, memory_order_seq_cst); | |
322 | } | |
323 | // @} | |
324 | ||
325 | // @} group pointer_abstractions | |
326 | ||
327 | _GLIBCXX_END_NAMESPACE_VERSION | |
328 | } // namespace | |
329 | ||
330 | #endif // _SHARED_PTR_ATOMIC_H |