Sort #include lines
[folly.git] / folly / experimental / hazptr / test / HazptrTest.cpp
index ddd06421191eba63266ebdf19f0a992b040d756f..d8ca18dacf7ad406bab73c24aeadbd07d3b021b6 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <folly/experimental/hazptr/test/HazptrUse1.h>
-#include <folly/experimental/hazptr/test/HazptrUse2.h>
+#define HAZPTR_DEBUG true
+#define HAZPTR_STATS true
+#define HAZPTR_SCAN_THRESHOLD 10
+
+#include <folly/experimental/hazptr/debug.h>
 #include <folly/experimental/hazptr/example/LockFreeLIFO.h>
 #include <folly/experimental/hazptr/example/SWMRList.h>
 #include <folly/experimental/hazptr/example/WideCAS.h>
-#include <folly/experimental/hazptr/debug.h>
 #include <folly/experimental/hazptr/hazptr.h>
+#include <folly/experimental/hazptr/test/HazptrUse1.h>
+#include <folly/experimental/hazptr/test/HazptrUse2.h>
 
-#include <gflags/gflags.h>
+#include <folly/portability/GFlags.h>
 #include <folly/portability/GTest.h>
 
 #include <thread>
 
-DEFINE_int32(num_threads, 1, "Number of threads");
+DEFINE_int32(num_threads, 5, "Number of threads");
 DEFINE_int64(num_reps, 1, "Number of test reps");
 DEFINE_int64(num_ops, 10, "Number of ops or pairs of ops per rep");
 
 using namespace folly::hazptr;
 
-TEST(Hazptr, Test1) {
-  DEBUG_PRINT("========== start of scope");
+class HazptrTest : public testing::Test {
+ public:
+  HazptrTest() : Test() {
+    DEBUG_PRINT("========== start of test scope");
+  }
+  ~HazptrTest() override {
+    DEBUG_PRINT("========== end of test scope");
+  }
+};
+
+TEST_F(HazptrTest, Test1) {
   DEBUG_PRINT("");
   Node1* node0 = (Node1*)malloc(sizeof(Node1));
   DEBUG_PRINT("=== new    node0 " << node0 << " " << sizeof(*node0));
@@ -61,13 +74,13 @@ TEST(Hazptr, Test1) {
   DEBUG_PRINT("");
 
   DEBUG_PRINT("=== hptr0");
-  hazptr_owner<Node1> hptr0;
+  hazptr_holder hptr0;
   DEBUG_PRINT("=== hptr1");
-  hazptr_owner<Node1> hptr1(myDomain0);
+  hazptr_holder hptr1(myDomain0);
   DEBUG_PRINT("=== hptr2");
-  hazptr_owner<Node1> hptr2(myDomain1);
+  hazptr_holder hptr2(myDomain1);
   DEBUG_PRINT("=== hptr3");
-  hazptr_owner<Node1> hptr3;
+  hazptr_holder hptr3;
 
   DEBUG_PRINT("");
 
@@ -78,11 +91,12 @@ TEST(Hazptr, Test1) {
 
   if (hptr0.try_protect(n0, shared0)) {}
   if (hptr1.try_protect(n1, shared1)) {}
-  hptr1.clear();
-  hptr1.set(n2);
+  hptr1.reset();
+  hptr1.reset(nullptr);
+  hptr1.reset(n2);
   if (hptr2.try_protect(n3, shared3)) {}
   swap(hptr1, hptr2);
-  hptr3.clear();
+  hptr3.reset();
 
   DEBUG_PRINT("");
 
@@ -94,12 +108,9 @@ TEST(Hazptr, Test1) {
   n2->retire(myDomain0);
   DEBUG_PRINT("=== retire n3 " << n3);
   n3->retire(myDomain1);
-
-  DEBUG_PRINT("========== end of scope");
 }
 
-TEST(Hazptr, Test2) {
-  DEBUG_PRINT("========== start of scope");
+TEST_F(HazptrTest, Test2) {
   Node2* node0 = new Node2;
   DEBUG_PRINT("=== new    node0 " << node0 << " " << sizeof(*node0));
   Node2* node1 = (Node2*)malloc(sizeof(Node2));
@@ -126,13 +137,13 @@ TEST(Hazptr, Test2) {
   DEBUG_PRINT("");
 
   DEBUG_PRINT("=== hptr0");
-  hazptr_owner<Node2> hptr0;
+  hazptr_holder hptr0;
   DEBUG_PRINT("=== hptr1");
-  hazptr_owner<Node2> hptr1(mineDomain0);
+  hazptr_holder hptr1(mineDomain0);
   DEBUG_PRINT("=== hptr2");
-  hazptr_owner<Node2> hptr2(mineDomain1);
+  hazptr_holder hptr2(mineDomain1);
   DEBUG_PRINT("=== hptr3");
-  hazptr_owner<Node2> hptr3;
+  hazptr_holder hptr3;
 
   DEBUG_PRINT("");
 
@@ -143,11 +154,11 @@ TEST(Hazptr, Test2) {
 
   if (hptr0.try_protect(n0, shared0)) {}
   if (hptr1.try_protect(n1, shared1)) {}
-  hptr1.clear();
-  hptr1.set(n2);
+  hptr1.reset();
+  hptr1.reset(n2);
   if (hptr2.try_protect(n3, shared3)) {}
   swap(hptr1, hptr2);
-  hptr3.clear();
+  hptr3.reset();
 
   DEBUG_PRINT("");
 
@@ -159,13 +170,10 @@ TEST(Hazptr, Test2) {
   n2->retire(mineDomain0, &mineReclaimFnFree);
   DEBUG_PRINT("=== retire n3 " << n3);
   n3->retire(mineDomain1, &mineReclaimFnFree);
-
-  DEBUG_PRINT("========== end of scope");
 }
 
-TEST(Hazptr, LIFO) {
+TEST_F(HazptrTest, LIFO) {
   using T = uint32_t;
-  DEBUG_PRINT("========== start of test scope");
   CHECK_GT(FLAGS_num_threads, 0);
   for (int i = 0; i < FLAGS_num_reps; ++i) {
     DEBUG_PRINT("========== start of rep scope");
@@ -185,12 +193,10 @@ TEST(Hazptr, LIFO) {
     }
     DEBUG_PRINT("========== end of rep scope");
   }
-  DEBUG_PRINT("========== end of test scope");
 }
 
-TEST(Hazptr, SWMRLIST) {
+TEST_F(HazptrTest, SWMRLIST) {
   using T = uint64_t;
-  DEBUG_PRINT("========== start of test scope");
   hazptr_domain custom_domain;
 
   CHECK_GT(FLAGS_num_threads, 0);
@@ -216,12 +222,9 @@ TEST(Hazptr, SWMRLIST) {
     }
     DEBUG_PRINT("========== end of rep scope");
   }
-  DEBUG_PRINT("========== end of test scope");
 }
 
-TEST(Hazptr, WIDECAS) {
-  DEBUG_PRINT("========== start of test scope");
-
+TEST_F(HazptrTest, WIDECAS) {
   WideCAS s;
   std::string u = "";
   std::string v = "11112222";
@@ -239,15 +242,79 @@ TEST(Hazptr, WIDECAS) {
   v = "333344445555";
   ret = s.cas(u, v);
   CHECK(ret);
+}
+
+TEST_F(HazptrTest, VirtualTest) {
+  struct Thing : public hazptr_obj_base<Thing> {
+    virtual ~Thing() {
+      DEBUG_PRINT("this: " << this << " &a: " << &a << " a: " << a);
+    }
+    int a;
+  };
+  for (int i = 0; i < 100; i++) {
+    auto bar = new Thing;
+    bar->a = i;
+
+    hazptr_holder hptr;
+    hptr.reset(bar);
+    bar->retire();
+    EXPECT_EQ(bar->a, i);
+  }
+}
 
-  DEBUG_PRINT("========== end of test scope");
+void destructionTest(hazptr_domain& domain) {
+  struct Thing : public hazptr_obj_base<Thing> {
+    Thing* next;
+    hazptr_domain* domain;
+    int val;
+    Thing(int v, Thing* n, hazptr_domain* d) : next(n), domain(d), val(v) {}
+    ~Thing() {
+      DEBUG_PRINT("this: " << this << " val: " << val << " next: " << next);
+      if (next) {
+        next->retire(*domain);
+      }
+    }
+  };
+  Thing* last{nullptr};
+  for (int i = 0; i < 2000; i++) {
+    last = new Thing(i, last, &domain);
+  }
+  last->retire(domain);
+}
+
+TEST_F(HazptrTest, DestructionTest) {
+  {
+    hazptr_domain myDomain0;
+    destructionTest(myDomain0);
+  }
+  destructionTest(default_hazptr_domain());
 }
 
-int main(int argc, char** argv) {
-  DEBUG_PRINT("================================================= start main");
-  testing::InitGoogleTest(&argc, argv);
-  google::ParseCommandLineFlags(&argc, &argv, true);
-  auto ret = RUN_ALL_TESTS();
-  DEBUG_PRINT("================================================= end main");
-  return ret;
+TEST_F(HazptrTest, Move) {
+  struct Foo : hazptr_obj_base<Foo> {
+    int a;
+  };
+  for (int i = 0; i < 100; ++i) {
+    Foo* x = new Foo;
+    x->a = i;
+    hazptr_holder hptr0;
+    // Protect object
+    hptr0.reset(x);
+    // Retire object
+    x->retire();
+    // Move constructor - still protected
+    hazptr_holder hptr1(std::move(hptr0));
+    // Self move is no-op - still protected
+    hazptr_holder* phptr1 = &hptr1;
+    CHECK_EQ(phptr1, &hptr1);
+    hptr1 = std::move(*phptr1);
+    // Empty constructor
+    hazptr_holder hptr2(nullptr);
+    // Move assignment - still protected
+    hptr2 = std::move(hptr1);
+    // Access object
+    CHECK_EQ(x->a, i);
+    // Unprotect object - hptr2 is nonempty
+    hptr2.reset();
+  }
 }