Ejemplo n.º 1
0
TEST_F(HazptrTest, basic_refcount) {
  constructed.store(0);
  destroyed.store(0);

  Foo* p = nullptr;
  int num = 20;
  for (int i = 0; i < num; ++i) {
    p = new Foo(i, p);
    if (i & 1) {
      p->acquire_ref_safe();
    } else {
      p->acquire_ref();
    }
  }
  hazptr_holder hptr;
  hptr.reset(p);
  for (auto q = p->next_; q; q = q->next_) {
    q->retire();
  }
  int v = num;
  for (auto q = p; q; q = q->next_) {
    CHECK_GT(v, 0);
    --v;
    CHECK_EQ(q->val_, v);
  }
  CHECK(!p->release_ref());
  CHECK_EQ(constructed.load(), num);
  CHECK_EQ(destroyed.load(), 0);
  p->retire();
  CHECK_EQ(constructed.load(), num);
  CHECK_EQ(destroyed.load(), 0);
  hptr.reset();

  /* retire enough objects to guarantee reclamation of Foo objects */
  for (int i = 0; i < 100; ++i) {
    auto a = new Dummy;
    a->retire();
  }

  CHECK_EQ(constructed.load(), num);
  CHECK_EQ(destroyed.load(), num);
}
Ejemplo n.º 2
0
TEST_F(HazptrTest, mt_refcount) {
  constructed.store(0);
  destroyed.store(0);

  std::atomic<bool> ready(false);
  std::atomic<int> setHazptrs(0);
  std::atomic<Foo*> head;

  int num = 20;
  int nthr = 10;
  std::vector<std::thread> thr(nthr);
  for (int i = 0; i < nthr; ++i) {
    thr[i] = std::thread([&] {
      while (!ready.load()) {
        /* spin */
      }
      hazptr_holder hptr;
      auto p = hptr.get_protected(head);
      ++setHazptrs;
      /* Concurrent with removal */
      int v = num;
      for (auto q = p; q; q = q->next_) {
        CHECK_GT(v, 0);
        --v;
        CHECK_EQ(q->val_, v);
      }
      CHECK_EQ(v, 0);
    });
  }

  Foo* p = nullptr;
  for (int i = 0; i < num; ++i) {
    p = new Foo(i, p);
    p->acquire_ref_safe();
  }
  head.store(p);

  ready.store(true);

  while (setHazptrs.load() < nthr) {
    /* spin */
  }

  /* this is concurrent with traversal by reader */
  head.store(nullptr);
  for (auto q = p; q; q = q->next_) {
    q->retire();
  }
  HAZPTR_DEBUG_PRINT("Foo should not be destroyed");
  CHECK_EQ(constructed.load(), num);
  CHECK_EQ(destroyed.load(), 0);

  HAZPTR_DEBUG_PRINT("Foo may be destroyed after releasing the last reference");
  if (p->release_ref()) {
    delete p;
  }

  /* retire enough objects to guarantee reclamation of Foo objects */
  for (int i = 0; i < 100; ++i) {
    auto a = new Dummy;
    a->retire();
  }

  for (int i = 0; i < nthr; ++i) {
    thr[i].join();
  }

  CHECK_EQ(constructed.load(), num);
  CHECK_EQ(destroyed.load(), num);
}