Skip to content

Commit

Permalink
make ThreadLocal move-ctor/assign noexcept and clear ctor
Browse files Browse the repository at this point in the history
Summary: Depending on the implementation of the standard library, move-constructing from `std::function` may not be enough to clear it. To enforce, we use `std::exchange`.

Differential Revision: D64845407

fbshipit-source-id: 85d787e07cf8f38290cc496b7ffccfa0c87b7b8c
  • Loading branch information
yfeldblum authored and facebook-github-bot committed Oct 24, 2024
1 parent 09546ed commit ac593b8
Showing 1 changed file with 22 additions and 9 deletions.
31 changes: 22 additions & 9 deletions folly/ThreadLocal.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,23 @@ class ThreadLocalPtr;
template <class T, class Tag = void, class AccessMode = void>
class ThreadLocal {
public:
constexpr ThreadLocal() : constructor_([]() { return T(); }) {}
constexpr ThreadLocal() noexcept : constructor_([]() { return T(); }) {}

template <typename F, std::enable_if_t<is_invocable_r_v<T, F>, int> = 0>
explicit ThreadLocal(F&& constructor)
: constructor_(std::forward<F>(constructor)) {}

ThreadLocal(ThreadLocal&& that) noexcept
: tlp_{std::move(that.tlp_)},
constructor_{std::exchange(that.constructor_, {})} {}

ThreadLocal& operator=(ThreadLocal&& that) noexcept {
assert(this != &that);
tlp_ = std::exchange(that.tlp_, {});
constructor_ = std::exchange(that.constructor_, {});
return *this;
}

FOLLY_ERASE T* get() const {
auto const ptr = tlp_.get();
return FOLLY_LIKELY(!!ptr) ? ptr : makeTlp();
Expand All @@ -90,10 +101,6 @@ class ThreadLocal {
typedef typename ThreadLocalPtr<T, Tag, AccessMode>::Accessor Accessor;
Accessor accessAllThreads() const { return tlp_.accessAllThreads(); }

// movable
ThreadLocal(ThreadLocal&&) = default;
ThreadLocal& operator=(ThreadLocal&&) = default;

private:
// non-copyable
ThreadLocal(const ThreadLocal&) = delete;
Expand Down Expand Up @@ -143,13 +150,13 @@ class ThreadLocalPtr {
using AccessAllThreadsEnabled = Negation<std::is_same<Tag, void>>;

public:
constexpr ThreadLocalPtr() : id_() {}
constexpr ThreadLocalPtr() noexcept : id_() {}

ThreadLocalPtr(ThreadLocalPtr&& other) noexcept : id_(std::move(other.id_)) {}

ThreadLocalPtr& operator=(ThreadLocalPtr&& other) {
ThreadLocalPtr& operator=(ThreadLocalPtr&& other) noexcept {
assert(this != &other);
destroy();
destroy(); // user-provided dtors invoked within here must not throw
id_ = std::move(other.id_);
return *this;
}
Expand Down Expand Up @@ -461,7 +468,13 @@ class ThreadLocalPtr {
}

private:
void destroy() { StaticMeta::instance().destroy(&id_); }
void destroy() noexcept {
auto const val = id_.value.load(std::memory_order_relaxed);
if (val == threadlocal_detail::kEntryIDInvalid) {
return;
}
StaticMeta::instance().destroy(&id_);
}

// non-copyable
ThreadLocalPtr(const ThreadLocalPtr&) = delete;
Expand Down

0 comments on commit ac593b8

Please sign in to comment.