Skip to content

Commit

Permalink
atomic_shared_ptr fallback
Browse files Browse the repository at this point in the history
Summary: A fallback implementation of `atomic_shared_ptr` for platforms other than libstdc++.

Reviewed By: skrueger

Differential Revision: D65844342

fbshipit-source-id: 09988ac5c1ce60c01aecba844901b53a377d2308
  • Loading branch information
yfeldblum authored and facebook-github-bot committed Nov 14, 2024
1 parent 334481f commit dbf2583
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 13 deletions.
97 changes: 97 additions & 0 deletions folly/concurrency/AtomicSharedPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,17 @@
#include <folly/concurrency/detail/AtomicSharedPtr-detail.h>
#include <folly/memory/SanitizeLeak.h>
#include <folly/synchronization/AtomicStruct.h>
#include <folly/synchronization/AtomicUtil.h>
#include <folly/synchronization/detail/AtomicUtils.h>

#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
Expand Down Expand Up @@ -385,3 +394,91 @@ class atomic_shared_ptr {
};

} // namespace folly

#else

namespace folly {

template <typename T>
class atomic_shared_ptr {
private:
std::shared_ptr<T> rep_;

public:
using value_type = std::shared_ptr<T>;

atomic_shared_ptr() = default;
atomic_shared_ptr(std::nullptr_t) noexcept {}
atomic_shared_ptr(std::shared_ptr<T> 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<T> desired) noexcept {
store(std::move(desired));
}

void operator=(atomic_shared_ptr const&) = delete;
void operator=(atomic_shared_ptr&&) = delete;

/* implicit */ operator std::shared_ptr<T>() const noexcept { return load(); }

bool is_lock_free() const noexcept { return atomic_is_lock_free(&rep_); }

std::shared_ptr<T> load(
std::memory_order order = std::memory_order_seq_cst) const noexcept {
return atomic_load_explicit(&rep_, order);
}

void store(
std::shared_ptr<T> desired,
std::memory_order order = std::memory_order_seq_cst) noexcept {
atomic_store_explicit(&rep_, std::move(desired), order);
}

std::shared_ptr<T> exchange(
std::shared_ptr<T> 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<T>& expected,
std::shared_ptr<T> 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<T>& expected,
std::shared_ptr<T> 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<T>& expected,
std::shared_ptr<T> 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<T>& expected,
std::shared_ptr<T> 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
4 changes: 4 additions & 0 deletions folly/concurrency/detail/AtomicSharedPtr-detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include <folly/lang/SafeAssert.h>

#if defined(__GLIBCXX__)

namespace folly {
namespace detail {

Expand Down Expand Up @@ -210,3 +212,5 @@ shared_ptr_internals::get_shared_ptr_from_counted_base(

} // namespace detail
} // namespace folly

#endif // defined(__GLIBCXX__)
27 changes: 14 additions & 13 deletions folly/concurrency/test/AtomicSharedPtrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <folly/Portability.h>
#include <folly/portability/Config.h>
#if defined(__GLIBCXX__) && (FOLLY_X64 || FOLLY_PPC64 || FOLLY_AARCH64)

#include <folly/concurrency/test/AtomicSharedPtrCounted.h>
#include <folly/concurrency/AtomicSharedPtr.h>

#include <atomic>
#include <memory>
#include <thread>

#include <folly/concurrency/AtomicSharedPtr.h>
#include <folly/Portability.h>
#include <folly/concurrency/test/AtomicSharedPtrCounted.h>
#include <folly/portability/Config.h>
#include <folly/portability/GFlags.h>
#include <folly/portability/GTest.h>

#include <folly/test/DeterministicSchedule.h>

using namespace folly;
Expand All @@ -52,7 +45,9 @@ struct foo {

TEST(AtomicSharedPtr, operators) {
atomic_shared_ptr<int> fooptr;
#if FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED
EXPECT_TRUE(fooptr.is_lock_free());
#endif
auto i = new int(5);
std::shared_ptr<int> s(i);
fooptr.store(s);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -119,6 +116,8 @@ TEST(AtomicSharedPtr, counted2) {
fooptr.load();
}

#endif

TEST(AtomicSharedPtr, ConstTest) {
const auto a(std::make_shared<foo>());
atomic_shared_ptr<foo> atom;
Expand Down Expand Up @@ -168,6 +167,8 @@ TEST(AtomicSharedPtr, AliasingWithNullptrConstructorTest) {
EXPECT_EQ(d_count, 1);
}

#if FOLLY_HAS_ATOMIC_SHARED_PTR_HOOKED

TEST(AtomicSharedPtr, MaxPtrs) {
shared_ptr<long> p(new long);
int max_atomic_shared_ptrs = 262144;
Expand Down Expand Up @@ -206,6 +207,8 @@ TEST(AtomicSharedPtr, DeterministicTest) {
}
}

#endif

TEST(AtomicSharedPtr, StressTest) {
constexpr size_t kExternalOffset = 0x2000;

Expand Down Expand Up @@ -253,5 +256,3 @@ TEST(AtomicSharedPtr, Leak) {
ptr.store(std::make_shared<int>(3), std::memory_order_relaxed);
EXPECT_EQ(3, *ptr.load(std::memory_order_relaxed));
}

#endif // defined(__GLIBCXX__)

0 comments on commit dbf2583

Please sign in to comment.