File: sanitize_test.cpp

package info (click to toggle)
xenium 0.0.2%2Bds-10
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,152 kB
  • sloc: cpp: 12,299; makefile: 20
file content (107 lines) | stat: -rw-r--r-- 3,136 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <xenium/detail/port.hpp>

/*
 * These tests are only compiled when ThreadSanitizer is active.
 * They are supposed to verify experimentally (via TSan) that the reclamation schemes
 * ensure the required happens-before relation between the destruction of a guard_ptr
 * to some node and the actual reclamation of that node.
 */

#ifdef __SANITIZE_THREAD__

#include <xenium/reclamation/lock_free_ref_count.hpp>
#include <xenium/reclamation/hazard_pointer.hpp>
#include <xenium/reclamation/hazard_eras.hpp>
#include <xenium/reclamation/generic_epoch_based.hpp>
#include <xenium/reclamation/quiescent_state_based.hpp>
#include <xenium/reclamation/stamp_it.hpp>

#include <gtest/gtest.h>

#include <array>
#include <thread>

namespace {

template <typename Reclaimer>
struct Sanitize : testing::Test {};

using Reclaimers = ::testing::Types<
  xenium::reclamation::lock_free_ref_count<>,
  xenium::reclamation::hazard_pointer<>::with<
    xenium::policy::allocation_strategy<xenium::reclamation::hp_allocation::static_strategy<3, 2, 1>>>,
  xenium::reclamation::hazard_eras<>::with<
    xenium::policy::allocation_strategy<xenium::reclamation::he_allocation::static_strategy<3, 2, 1>>>,
  xenium::reclamation::debra<>::with<xenium::policy::scan_frequency<1>>,
  xenium::reclamation::epoch_based<>::with<xenium::policy::scan_frequency<1>>,
  xenium::reclamation::new_epoch_based<>::with<xenium::policy::scan_frequency<1>>,
  xenium::reclamation::quiescent_state_based,
  xenium::reclamation::stamp_it
>;
TYPED_TEST_CASE(Sanitize, Reclaimers);

#ifdef DEBUG
  const int MaxIterations = 1000;
#else
  const int MaxIterations = 10000;
#endif

TYPED_TEST(Sanitize, guard_ptrs)
{
  struct node : TypeParam::template enable_concurrent_ptr<node, 1> {
    int dummy;
  };

  for (int x = 0; x < 10; ++x) {
    using concurrent_ptr = typename TypeParam::template concurrent_ptr<node, 1>;
    using guard_ptr = typename concurrent_ptr::guard_ptr;

    constexpr int NumPtrs = 10;
    std::array<concurrent_ptr, NumPtrs> ptrs;

    std::thread t1([&ptrs]() {
      node* n = new node();
      for (int i = 0; i < MaxIterations; ++i) {
        guard_ptr guard;
        for (int j = 0; j < NumPtrs; ++j) {
          if (ptrs[j].load(std::memory_order_relaxed) == nullptr) {
            ptrs[j].store(n, std::memory_order_release);
            n = new node();
          }
        }
      }
    });

    std::thread t2([&ptrs]() {
      for (int i = 0; i < MaxIterations; ++i) {
        guard_ptr guard;
        for (int j = 0; j < NumPtrs; ++j) {
          guard.acquire(ptrs[j], std::memory_order_acquire);
          if (guard)
            guard->dummy = 42;
        }
      }
    });

    std::thread t3([&ptrs]() {
      for (int i = 0; i < MaxIterations; ++i) {
        guard_ptr guard;
        for (int j = 0; j < NumPtrs; ++j) {
          guard.acquire(ptrs[j], std::memory_order_acquire);
          if (guard) {
            ptrs[j].store(nullptr, std::memory_order_relaxed);
            guard_ptr copy = guard;
            copy.reclaim();
          }
        }
      }
    });

    t1.join();
    t2.join();
    t3.join();
  }
}

}
#endif