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