Commit 8635022f authored by Maged Michael's avatar Maged Michael Committed by Facebook Github Bot

hazptr: Fix hazptr_cleanup

Summary:
Added missing steps for registering and deregistering per-thread hazptr_priv structures with the default domain.
Updated tests to detect the error

Reviewed By: djwatson, davidtgoldblatt

Differential Revision: D6965459

fbshipit-source-id: 6eb6a5981c1d22518f318ace7387a3941a013352
parent a12a2a09
...@@ -183,6 +183,7 @@ class hazptr_priv { ...@@ -183,6 +183,7 @@ class hazptr_priv {
tail_ = nullptr; tail_ = nullptr;
rcount_ = 0; rcount_ = 0;
active_ = true; active_ = true;
default_hazptr_domain().priv_add(this);
} }
bool active() { bool active() {
...@@ -932,6 +933,14 @@ inline void hazptr_domain::cleanup() { ...@@ -932,6 +933,14 @@ inline void hazptr_domain::cleanup() {
bulkReclaim(); bulkReclaim();
} }
inline void hazptr_domain::priv_add(hazptr_priv* rec) {
priv_.insert(rec);
}
inline void hazptr_domain::priv_remove(hazptr_priv* rec) {
priv_.remove(rec);
}
inline hazptr_rec* hazptr_domain::hazptrAcquire() { inline hazptr_rec* hazptr_domain::hazptrAcquire() {
hazptr_rec* p; hazptr_rec* p;
hazptr_rec* next; hazptr_rec* next;
...@@ -1174,7 +1183,6 @@ FOLLY_ALWAYS_INLINE hazptr_tc* hazptr_tc_tls() { ...@@ -1174,7 +1183,6 @@ FOLLY_ALWAYS_INLINE hazptr_tc* hazptr_tc_tls() {
} }
inline void hazptr_tc_init() { inline void hazptr_tc_init() {
HAZPTR_DEBUG_PRINT("");
auto& tc = tls_tc_data_; auto& tc = tls_tc_data_;
HAZPTR_DEBUG_PRINT(&tc); HAZPTR_DEBUG_PRINT(&tc);
tc.count_ = 0; tc.count_ = 0;
...@@ -1231,6 +1239,7 @@ inline void hazptr_priv_shutdown() { ...@@ -1231,6 +1239,7 @@ inline void hazptr_priv_shutdown() {
if (!priv.empty()) { if (!priv.empty()) {
priv.push_all_to_domain(); priv.push_all_to_domain();
} }
default_hazptr_domain().priv_remove(&priv);
} }
inline bool hazptr_priv_try_retire(hazptr_obj* obj) { inline bool hazptr_priv_try_retire(hazptr_obj* obj) {
......
...@@ -90,6 +90,8 @@ class hazptr_domain { ...@@ -90,6 +90,8 @@ class hazptr_domain {
template <typename T, typename D = std::default_delete<T>> template <typename T, typename D = std::default_delete<T>>
void retire(T* obj, D reclaim = {}); void retire(T* obj, D reclaim = {});
void cleanup(); void cleanup();
void priv_add(hazptr_priv* rec);
void priv_remove(hazptr_priv* rec);
private: private:
friend class hazptr_obj_batch; friend class hazptr_obj_batch;
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
DEFINE_int32(num_threads, 5, "Number of threads"); DEFINE_int32(num_threads, 5, "Number of threads");
DEFINE_int64(num_reps, 1, "Number of test reps"); DEFINE_int64(num_reps, 1, "Number of test reps");
DEFINE_int64(num_ops, 10, "Number of ops or pairs of ops per rep"); DEFINE_int64(num_ops, 1007, "Number of ops or pairs of ops per rep");
using namespace folly::hazptr; using namespace folly::hazptr;
...@@ -443,11 +443,11 @@ struct Foo : hazptr_obj_base_refcounted<Foo> { ...@@ -443,11 +443,11 @@ struct Foo : hazptr_obj_base_refcounted<Foo> {
Foo* next_; Foo* next_;
Foo(int v, Foo* n) : val_(v), marked_(false), next_(n) { Foo(int v, Foo* n) : val_(v), marked_(false), next_(n) {
HAZPTR_DEBUG_PRINT(""); HAZPTR_DEBUG_PRINT("");
++constructed; constructed.fetch_add(1);
} }
~Foo() { ~Foo() {
HAZPTR_DEBUG_PRINT(""); HAZPTR_DEBUG_PRINT("");
++destroyed; destroyed.fetch_add(1);
if (marked_) { if (marked_) {
return; return;
} }
...@@ -604,21 +604,39 @@ TEST_F(HazptrTest, FreeFunctionRetire) { ...@@ -604,21 +604,39 @@ TEST_F(HazptrTest, FreeFunctionRetire) {
TEST_F(HazptrTest, FreeFunctionCleanup) { TEST_F(HazptrTest, FreeFunctionCleanup) {
CHECK_GT(FLAGS_num_threads, 0); CHECK_GT(FLAGS_num_threads, 0);
int threadOps = 1007;
int mainOps = 19;
constructed.store(0); constructed.store(0);
destroyed.store(0); destroyed.store(0);
std::atomic<int> threadsDone{0};
std::atomic<bool> mainDone{false};
std::vector<std::thread> threads(FLAGS_num_threads); std::vector<std::thread> threads(FLAGS_num_threads);
for (int tid = 0; tid < FLAGS_num_threads; ++tid) { for (int tid = 0; tid < FLAGS_num_threads; ++tid) {
threads[tid] = std::thread([&, tid]() { threads[tid] = std::thread([&, tid]() {
for (int j = tid; j < FLAGS_num_ops; j += FLAGS_num_threads) { for (int j = tid; j < threadOps; j += FLAGS_num_threads) {
auto p = new Foo(j, nullptr); auto p = new Foo(j, nullptr);
p->retire(); p->retire();
} }
threadsDone.fetch_add(1);
while (!mainDone.load()) {
/* spin */;
}
}); });
} }
{ // include the main thread in the test
for (int i = 0; i < mainOps; ++i) {
auto p = new Foo(0, nullptr);
p->retire();
}
}
while (threadsDone.load() < FLAGS_num_threads) {
/* spin */;
}
CHECK_EQ(constructed.load(), threadOps + mainOps);
hazptr_cleanup();
CHECK_EQ(destroyed.load(), threadOps + mainOps);
mainDone.store(true);
for (auto& t : threads) { for (auto& t : threads) {
t.join(); t.join();
} }
CHECK_EQ(constructed.load(), FLAGS_num_ops);
hazptr_cleanup();
CHECK_EQ(destroyed.load(), FLAGS_num_ops);
} }
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