Domain destruction fixes
authorDave Watson <davejwatson@fb.com>
Wed, 3 May 2017 17:57:29 +0000 (10:57 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Wed, 3 May 2017 18:06:24 +0000 (11:06 -0700)
Summary:
If a retired object's destructor retire()s other hazard pointers, currently
these are not cleaned up correctly when the domain destructs.

Retired pointers must be cleaned up before destroying hazptr_recs, and must be done
iteratively until no more garbage is generated.

Reviewed By: magedm

Differential Revision: D4987333

fbshipit-source-id: bcdd61abb47caca0892a8c4dbb864d17d4f2fa30

folly/experimental/hazptr/hazptr-impl.h
folly/experimental/hazptr/test/HazptrTest.cpp

index ecf6865..50874df 100644 (file)
@@ -183,6 +183,17 @@ inline const void* hazptr_obj::getObjPtr() const {
 
 inline hazptr_domain::~hazptr_domain() {
   DEBUG_PRINT(this);
+  { /* reclaim all remaining retired objects */
+    hazptr_obj* next;
+    auto retired = retired_.exchange(nullptr);
+    while (retired) {
+      for (auto p = retired; p; p = next) {
+        next = p->next_;
+        (*(p->reclaim_))(p);
+      }
+      retired = retired_.exchange(nullptr);
+    }
+  }
   { /* free all hazptr_rec-s */
     hazptr_rec* next;
     for (auto p = hazptrs_.load(); p; p = next) {
@@ -190,13 +201,6 @@ inline hazptr_domain::~hazptr_domain() {
       mr_->deallocate(static_cast<void*>(p), sizeof(hazptr_rec));
     }
   }
-  { /* reclaim all remaining retired objects */
-    hazptr_obj* next;
-    for (auto p = retired_.load(); p; p = next) {
-      next = p->next_;
-      (*(p->reclaim_))(p);
-    }
-  }
 }
 
 inline void hazptr_domain::try_reclaim() {
index fa4ac1e..2050526 100644 (file)
@@ -256,3 +256,22 @@ TEST_F(HazptrTest, VirtualTest) {
     EXPECT_EQ(bar->a, i);
   }
 }
+
+TEST_F(HazptrTest, DestructionTest) {
+  hazptr_domain myDomain0;
+  struct Thing : public hazptr_obj_base<Thing> {
+    Thing* next;
+    Thing(Thing* n) : next(n) {}
+    ~Thing() {
+      DEBUG_PRINT("this: " << this << " next: " << next);
+      if (next) {
+        next->retire();
+      }
+    }
+  };
+  Thing* last{nullptr};
+  for (int i = 0; i < 2000; i++) {
+    last = new Thing(last);
+  }
+  last->retire();
+}