Add free-function retire
authorDave Watson <davejwatson@fb.com>
Mon, 20 Nov 2017 16:18:27 +0000 (08:18 -0800)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Mon, 20 Nov 2017 16:30:09 +0000 (08:30 -0800)
Summary:
Adds a hazptr_retire and domain::retire methods to hazptr.  They both allocate memory instead of inheriting.

This will make implementation of google's cell proposal trivial, vs. D4754972 which felt overwraught.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0561r0.html

Reviewed By: magedm

Differential Revision: D6361162

fbshipit-source-id: 9f259f434139f960483b2ab7c5190d3807edcf52

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

index e287aecc91c45d1d00d92bdac29b3f75f2532a64..823f2ebf68aa3a2781de014404e3f8762d590388 100644 (file)
@@ -602,6 +602,11 @@ FOLLY_ALWAYS_INLINE hazptr_domain& default_hazptr_domain() {
   return default_domain_;
 }
 
+template <typename T, typename D>
+FOLLY_ALWAYS_INLINE void hazptr_retire(T* obj, D reclaim) {
+  default_hazptr_domain().retire(obj, std::move(reclaim));
+}
+
 /** hazptr_rec */
 
 FOLLY_ALWAYS_INLINE void hazptr_rec::set(const void* p) noexcept {
@@ -649,6 +654,21 @@ inline const void* hazptr_obj::getObjPtr() const {
 
 /** hazptr_domain */
 
+template <typename T, typename D>
+void hazptr_domain::retire(T* obj, D reclaim) {
+  struct hazptr_retire_node : hazptr_obj {
+    std::unique_ptr<T, D> obj_;
+
+    hazptr_retire_node(T* obj, D reclaim) : obj_{obj, std::move(reclaim)} {}
+  };
+
+  auto node = new hazptr_retire_node(obj, std::move(reclaim));
+  node->reclaim_ = [](hazptr_obj* p) {
+    delete static_cast<hazptr_retire_node*>(p);
+  };
+  objRetire(node);
+}
+
 inline hazptr_domain::~hazptr_domain() {
   DEBUG_PRINT(this);
   { /* reclaim all remaining retired objects */
index 62d96514bc7ade485eb3f9fe8f7b643d07d444f4..48e8392ae48676fccd311e667e41e0f986ca2117 100644 (file)
@@ -62,6 +62,10 @@ class hazptr_domain {
   hazptr_domain& operator=(const hazptr_domain&) = delete;
   hazptr_domain& operator=(hazptr_domain&&) = delete;
 
+  /** Free-function retire.  May allocate memory */
+  template <typename T, typename D = std::default_delete<T>>
+  void retire(T* obj, D reclaim = {});
+
  private:
   friend class hazptr_holder;
   template <typename, typename>
@@ -90,6 +94,10 @@ hazptr_domain& default_hazptr_domain();
 
 extern hazptr_domain default_domain_;
 
+/** Free-function retire, that operates on the default domain */
+template <typename T, typename D = std::default_delete<T>>
+void hazptr_retire(T* obj, D reclaim = {});
+
 /** Definition of hazptr_obj */
 class hazptr_obj {
   friend class hazptr_domain;
index 9d71cda38b4d20581f959aa9db0aba9ad8c346e9..89ddc023bea2a75361c0a6d2b62d7eff60bb1cbb 100644 (file)
@@ -551,3 +551,25 @@ TEST_F(HazptrTest, mt_refcount) {
   CHECK_EQ(constructed.load(), num);
   CHECK_EQ(destroyed.load(), num);
 }
+
+TEST_F(HazptrTest, FreeFunctionRetire) {
+  auto foo = new int;
+  hazptr_retire(foo);
+  auto foo2 = new int;
+  hazptr_retire(foo2, [](int* obj) { delete obj; });
+
+  bool retired = false;
+  {
+    hazptr_domain myDomain0;
+    struct delret {
+      bool* retired_;
+      delret(bool* retire) : retired_(retire) {}
+      ~delret() {
+        *retired_ = true;
+      }
+    };
+    auto foo3 = new delret(&retired);
+    myDomain0.retire(foo3);
+  }
+  EXPECT_TRUE(retired);
+}