From dbf25839da7d5699991ea76df73a59216bf4f246 Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Thu, 14 Nov 2024 09:09:23 -0800 Subject: [PATCH] atomic_shared_ptr fallback Summary: A fallback implementation of `atomic_shared_ptr` for platforms other than libstdc++. Reviewed By: skrueger Differential Revision: D65844342 fbshipit-source-id: 09988ac5c1ce60c01aecba844901b53a377d2308 --- folly/concurrency/AtomicSharedPtr.h | 97 +++++++++++++++++++ .../detail/AtomicSharedPtr-detail.h | 4 + .../concurrency/test/AtomicSharedPtrTest.cpp | 27 +++--- 3 files changed, 115 insertions(+), 13 deletions(-) diff --git a/folly/concurrency/AtomicSharedPtr.h b/folly/concurrency/AtomicSharedPtr.h index afbc67e6963..dc9fd2d98c3 100644 --- a/folly/concurrency/AtomicSharedPtr.h +++ b/folly/concurrency/AtomicSharedPtr.h @@ -24,8 +24,17 @@ #include #include #include +#include #include +#if defined(__GLIBCXX__) && FOLLY_HAS_PACKED_SYNC_PTR +#define FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED 1 +#else +#define FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED 0 +#endif + +#if FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED + /* * This is an implementation of the std::atomic_shared_ptr TS * http://en.cppreference.com/w/cpp/experimental/atomic_shared_ptr @@ -385,3 +394,91 @@ class atomic_shared_ptr { }; } // namespace folly + +#else + +namespace folly { + +template +class atomic_shared_ptr { + private: + std::shared_ptr rep_; + + public: + using value_type = std::shared_ptr; + + atomic_shared_ptr() = default; + atomic_shared_ptr(std::nullptr_t) noexcept {} + atomic_shared_ptr(std::shared_ptr desired) noexcept + : rep_{std::move(desired)} {} + + atomic_shared_ptr(atomic_shared_ptr const&) = delete; + atomic_shared_ptr(atomic_shared_ptr&&) = delete; + + void operator=(std::nullptr_t) noexcept { store(nullptr); } + void operator=(std::shared_ptr desired) noexcept { + store(std::move(desired)); + } + + void operator=(atomic_shared_ptr const&) = delete; + void operator=(atomic_shared_ptr&&) = delete; + + /* implicit */ operator std::shared_ptr() const noexcept { return load(); } + + bool is_lock_free() const noexcept { return atomic_is_lock_free(&rep_); } + + std::shared_ptr load( + std::memory_order order = std::memory_order_seq_cst) const noexcept { + return atomic_load_explicit(&rep_, order); + } + + void store( + std::shared_ptr desired, + std::memory_order order = std::memory_order_seq_cst) noexcept { + atomic_store_explicit(&rep_, std::move(desired), order); + } + + std::shared_ptr exchange( + std::shared_ptr desired, + std::memory_order order = std::memory_order_seq_cst) noexcept { + return atomic_exchange_explicit(&rep_, std::move(desired), order); + } + + bool compare_exchange_weak( + std::shared_ptr& expected, + std::shared_ptr desired, + std::memory_order success, + std::memory_order failure) noexcept { + return atomic_compare_exchange_weak_explicit( + &rep_, &expected, std::move(desired), success, failure); + } + + bool compare_exchange_weak( + std::shared_ptr& expected, + std::shared_ptr desired, + std::memory_order order = std::memory_order_seq_cst) noexcept { + return atomic_compare_exchange_weak_explicit( + &rep_, &expected, std::move(desired), order, memory_order_load(order)); + } + + bool compare_exchange_strong( + std::shared_ptr& expected, + std::shared_ptr desired, + std::memory_order success, + std::memory_order failure) noexcept { + return atomic_compare_exchange_strong_explicit( + &rep_, &expected, std::move(desired), success, failure); + } + + bool compare_exchange_strong( + std::shared_ptr& expected, + std::shared_ptr desired, + std::memory_order order = std::memory_order_seq_cst) noexcept { + return atomic_compare_exchange_strong_explicit( + &rep_, &expected, std::move(desired), order, memory_order_load(order)); + } +}; + +} // namespace folly + +#endif // FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED diff --git a/folly/concurrency/detail/AtomicSharedPtr-detail.h b/folly/concurrency/detail/AtomicSharedPtr-detail.h index ced8cbd222f..e07542eaa15 100644 --- a/folly/concurrency/detail/AtomicSharedPtr-detail.h +++ b/folly/concurrency/detail/AtomicSharedPtr-detail.h @@ -22,6 +22,8 @@ #include +#if defined(__GLIBCXX__) + namespace folly { namespace detail { @@ -210,3 +212,5 @@ shared_ptr_internals::get_shared_ptr_from_counted_base( } // namespace detail } // namespace folly + +#endif // defined(__GLIBCXX__) diff --git a/folly/concurrency/test/AtomicSharedPtrTest.cpp b/folly/concurrency/test/AtomicSharedPtrTest.cpp index 5ed2f7994c4..db0643cd2c6 100644 --- a/folly/concurrency/test/AtomicSharedPtrTest.cpp +++ b/folly/concurrency/test/AtomicSharedPtrTest.cpp @@ -14,24 +14,17 @@ * limitations under the License. */ -// AtomicSharedPtr-detail.h only works with libstdc++, so skip these tests for -// other vendors -// PackedSyncPtr requires x64, ppc64 or aarch64, skip these tests for -// other arches -#include -#include -#if defined(__GLIBCXX__) && (FOLLY_X64 || FOLLY_PPC64 || FOLLY_AARCH64) - -#include +#include #include #include #include -#include +#include +#include +#include #include #include - #include using namespace folly; @@ -52,7 +45,9 @@ struct foo { TEST(AtomicSharedPtr, operators) { atomic_shared_ptr fooptr; +#if FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED EXPECT_TRUE(fooptr.is_lock_free()); +#endif auto i = new int(5); std::shared_ptr s(i); fooptr.store(s); @@ -90,6 +85,8 @@ TEST(AtomicSharedPtr, foo) { EXPECT_EQ(1, d_count); } +#if FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED + TEST(AtomicSharedPtr, counted) { c_count = 0; d_count = 0; @@ -119,6 +116,8 @@ TEST(AtomicSharedPtr, counted2) { fooptr.load(); } +#endif + TEST(AtomicSharedPtr, ConstTest) { const auto a(std::make_shared()); atomic_shared_ptr atom; @@ -168,6 +167,8 @@ TEST(AtomicSharedPtr, AliasingWithNullptrConstructorTest) { EXPECT_EQ(d_count, 1); } +#if FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED + TEST(AtomicSharedPtr, MaxPtrs) { shared_ptr p(new long); int max_atomic_shared_ptrs = 262144; @@ -206,6 +207,8 @@ TEST(AtomicSharedPtr, DeterministicTest) { } } +#endif + TEST(AtomicSharedPtr, StressTest) { constexpr size_t kExternalOffset = 0x2000; @@ -253,5 +256,3 @@ TEST(AtomicSharedPtr, Leak) { ptr.store(std::make_shared(3), std::memory_order_relaxed); EXPECT_EQ(3, *ptr.load(std::memory_order_relaxed)); } - -#endif // defined(__GLIBCXX__)