shared_ptr_atomic.h 9.6 KB

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