Commit b3833ef1 authored by Maged Michael's avatar Maged Michael Committed by Facebook GitHub Bot

hazard pointers: Eliminate thread local lists of retired objects

Summary:
Remove hazptr_priv, the thread-local list of retired objects.

Non-cohort retired objects are pushed directly into the domain.

Reviewed By: davidtgoldblatt

Differential Revision: D30806863

fbshipit-source-id: 526c90f5a198b4e42a55062cb7344e5286bf28fd
parent 4f4c0ff8
......@@ -119,14 +119,6 @@ class hazptr_tc;
template <template <typename> class Atom = std::atomic>
hazptr_tc<Atom>& hazptr_tc_tls();
/** hazptr_priv */
template <template <typename> class Atom = std::atomic>
class hazptr_priv;
/** hazptr_priv_tls */
template <template <typename> class Atom = std::atomic>
hazptr_priv<Atom>& hazptr_priv_tls();
///
/// Hazard pointer domain
/// Defined in HazptrDomain.h
......
......@@ -583,19 +583,6 @@ class hazptr_domain {
}
void relaxed_cleanup() noexcept {
#if FOLLY_HAZPTR_THR_LOCAL
hazptr_obj<Atom>* h = nullptr;
hazptr_obj<Atom>* t = nullptr;
for (hazptr_priv<Atom>& priv :
hazptr_priv_singleton<Atom>::accessAllThreads()) {
priv.collect(h, t);
}
if (h) {
DCHECK(t);
hazptr_obj_list<Atom> l(h, t, 0);
push_retired(l);
}
#endif
rcount_.store(0, std::memory_order_release);
bulk_reclaim(true);
}
......@@ -654,11 +641,6 @@ class hazptr_domain {
}
obj = next;
}
#if FOLLY_HAZPTR_THR_LOCAL
if (!shutdown_) {
hazptr_priv_tls<Atom>().push_all_to_domain(false);
}
#endif
bool done = ((children.count() == 0) && (retired() == nullptr));
matched.splice(children);
if (matched.count() > 0) {
......
......@@ -91,7 +91,6 @@ class hazptr_obj {
template <typename, template <typename> class, typename>
friend class hazptr_obj_base_linked;
friend class hazptr_obj_list<Atom>;
friend class hazptr_priv<Atom>;
friend class hazptr_detail::linked_list<Obj>;
friend class hazptr_detail::shared_head_only_list<Obj, Atom>;
friend class hazptr_detail::shared_head_tail_list<Obj, Atom>;
......@@ -150,7 +149,6 @@ class hazptr_obj {
template <typename, template <typename> class, typename>
friend class hazptr_obj_base_refcounted;
friend class hazptr_obj_cohort<Atom>;
friend class hazptr_priv<Atom>;
Obj* next() const noexcept { return next_; }
......@@ -178,12 +176,6 @@ class hazptr_obj {
}
void push_to_retired(hazptr_domain<Atom>& domain) {
#if FOLLY_HAZPTR_THR_LOCAL
if (&domain == &default_hazptr_domain<Atom>() && !domain.shutdown_) {
hazptr_priv_tls<Atom>().push(this);
return;
}
#endif
hazptr_obj_list<Atom> l(this);
hazptr_domain_push_retired(l, true, domain);
}
......
......@@ -160,151 +160,6 @@ FOLLY_ALWAYS_INLINE hazptr_tc<Atom>& hazptr_tc_tls() {
return folly::SingletonThreadLocal<hazptr_tc<Atom>, hazptr_tc_tls_tag>::get();
}
/**
* hazptr_priv
*
* Per-thread list of retired objects to be pushed in bulk to domain.
*/
template <template <typename> class Atom>
class hazptr_priv {
static constexpr int kThreshold = 20;
Atom<hazptr_obj<Atom>*> head_;
Atom<hazptr_obj<Atom>*> tail_;
int rcount_;
bool in_dtor_;
public:
hazptr_priv() : head_(nullptr), tail_(nullptr), rcount_(0), in_dtor_(false) {}
~hazptr_priv() {
in_dtor_ = true;
if (!empty()) {
push_all_to_domain(false);
}
}
private:
friend class hazptr_domain<Atom>;
friend class hazptr_obj<Atom>;
bool empty() const noexcept { return head() == nullptr; }
void push(hazptr_obj<Atom>* obj) {
DCHECK(!in_dtor_);
push_in_priv_list(obj);
}
void push_in_priv_list(hazptr_obj<Atom>* obj) {
while (true) {
if (tail()) {
if (push_in_non_empty_list(obj)) {
break;
}
} else {
if (push_in_empty_list(obj)) {
break;
}
}
}
if (++rcount_ >= kThreshold) {
push_all_to_domain(true);
}
}
void push_all_to_domain(bool check_to_reclaim) {
hazptr_obj<Atom>* h = nullptr;
hazptr_obj<Atom>* t = nullptr;
collect(h, t);
if (h) {
DCHECK(t);
hazptr_obj_list<Atom> l(h, t, rcount_);
hazptr_domain_push_retired<Atom>(l, check_to_reclaim);
rcount_ = 0;
}
}
void collect(
hazptr_obj<Atom>*& colHead, hazptr_obj<Atom>*& colTail) noexcept {
// This function doesn't change rcount_.
// The value rcount_ is accurate excluding the effects of calling collect().
auto h = exchange_head();
if (h) {
auto t = exchange_tail();
DCHECK(t);
if (colTail) {
colTail->set_next(h);
} else {
colHead = h;
}
colTail = t;
}
}
hazptr_obj<Atom>* head() const noexcept {
return head_.load(std::memory_order_acquire);
}
hazptr_obj<Atom>* tail() const noexcept {
return tail_.load(std::memory_order_acquire);
}
void set_head(hazptr_obj<Atom>* obj) noexcept {
head_.store(obj, std::memory_order_release);
}
bool cas_head(hazptr_obj<Atom>* expected, hazptr_obj<Atom>* obj) noexcept {
return head_.compare_exchange_weak(
expected, obj, std::memory_order_acq_rel, std::memory_order_relaxed);
}
bool cas_tail(hazptr_obj<Atom>* expected, hazptr_obj<Atom>* obj) noexcept {
return tail_.compare_exchange_weak(
expected, obj, std::memory_order_acq_rel, std::memory_order_relaxed);
}
hazptr_obj<Atom>* exchange_head() noexcept {
return head_.exchange(nullptr, std::memory_order_acq_rel);
}
hazptr_obj<Atom>* exchange_tail() noexcept {
return tail_.exchange(nullptr, std::memory_order_acq_rel);
}
bool push_in_non_empty_list(hazptr_obj<Atom>* obj) noexcept {
auto h = head();
if (h) {
obj->set_next(h);
if (cas_head(h, obj)) {
return true;
}
}
return false;
}
bool push_in_empty_list(hazptr_obj<Atom>* obj) noexcept {
hazptr_obj<Atom>* t = nullptr;
obj->set_next(nullptr);
if (cas_tail(t, obj)) {
set_head(obj);
return true;
}
return false;
}
}; // hazptr_priv
/** hazptr_priv_tls */
struct HazptrTag {};
template <template <typename> class Atom>
using hazptr_priv_singleton =
folly::SingletonThreadLocal<hazptr_priv<Atom>, HazptrTag>;
template <template <typename> class Atom>
FOLLY_ALWAYS_INLINE hazptr_priv<Atom>& hazptr_priv_tls() {
return hazptr_priv_singleton<Atom>::get();
}
} // namespace folly
#endif // FOLLY_HAZPTR_THR_LOCAL
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment