summaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/20_util/shared_ptr/atomic/atomic_shared_ptr.cc
blob: 1f97224bf6aad232640e6701404524b611a50447 (plain)
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// { dg-options "-std=gnu++20" }
// { dg-do run { target c++20 } }
// { dg-require-effective-target gthreads }
// { dg-additional-options "-pthread" { target pthread } }
// { dg-add-options libatomic }

#include <memory>

#ifndef __cpp_lib_atomic_shared_ptr
# error "Feature-test macro for atomic<shared_ptr<T>> missing in <memory>"
#elif __cpp_lib_atomic_shared_ptr != 201711L
# error "Feature-test macro for atomic<shared_ptr<T>> has wrong value in <memory>"
#endif

#include <thread>

#include <testsuite_hooks.h>

// Check constexpr constructor.
constinit std::atomic<std::shared_ptr<int>> a;

void
test_is_lock_free()
{
  using test_type = std::atomic<std::shared_ptr<int>>;
  static_assert( test_type::is_always_lock_free == false );

  test_type p;
  VERIFY( p.is_lock_free() == false );
}

void
test_atomic_shared_ptr()
{
  struct A { int a; int b; };

  auto a = std::make_shared<A>( 0, 42 );
  using ptr_t = std::shared_ptr<A>;
  {
    std::atomic<ptr_t> p{ };
    VERIFY( p.load().get() == nullptr );
  }

  std::atomic<ptr_t> p{ a };
  VERIFY( p.load().get() == a.get() );
  auto b = std::make_shared<A>( 42, 0 );
  p.store(b);
  VERIFY( p.load().get() != a.get() );
  VERIFY( p.load().get() == b.get() );
  p.exchange(a);
  VERIFY( p.load().get() != b.get() );
  VERIFY( p.load().get() == a.get() );

  {
    ptr_t aa{ a };
    VERIFY( p.compare_exchange_strong(aa, b,
				      std::memory_order_seq_cst,
				      std::memory_order_seq_cst) == true );
    ptr_t bb{ a };
    VERIFY( p.compare_exchange_strong(bb, b,
				      std::memory_order_seq_cst,
				      std::memory_order_seq_cst) == false );
    VERIFY( bb.get() == b.get() );
  }

  {
    ptr_t bb{ b };
    VERIFY( p.compare_exchange_weak(bb, a,
				    std::memory_order_seq_cst,
				    std::memory_order_seq_cst) == true );
    ptr_t aa{ b };
    VERIFY( p.compare_exchange_weak(aa, a,
				      std::memory_order_seq_cst,
				      std::memory_order_seq_cst) == false );
    VERIFY( aa.get() == a.get() );
  }
}

void
test_wait_notify()
{
  std::atomic<std::shared_ptr<int>> p;
  std::shared_ptr<int> a = std::make_shared<int>();
  std::shared_ptr<int> b = std::make_shared<int>();

  p.store(a);
  p.wait(b);
  std::thread t([&]
      {
	p.store(b);
	p.notify_one();
      });
  p.wait(a);
  t.join();
}

int counter = 0;

void
test_counting()
{
  struct X
  {
    ~X() { ++counter; }
  };

  {
    std::atomic<std::shared_ptr<X>> p{ std::make_shared<X>() };
    std::shared_ptr<X> a = p.load();
    VERIFY( a.use_count() == 2 ); // p, a
    p.store({});
    VERIFY( a.use_count() == 1 ); // a
    p.store(a);
    VERIFY( a.use_count() == 2 ); // p, a
    std::shared_ptr<X> b = std::make_shared<X>();
    std::shared_ptr<X> c = p.exchange(b);
    VERIFY( a.use_count() == 2 ); // a, c
    VERIFY( c == a );
    VERIFY( b.use_count() == 2 ); // p, b
    std::atomic<std::shared_ptr<X>> p2{a};
    VERIFY( a.use_count() == 3 ); // p2, a, c
    VERIFY( p2.compare_exchange_strong(a, b) );
    VERIFY( a.use_count() == 2 ); // a, c
    VERIFY( b.use_count() == 3 ); // p, p2, b
    VERIFY ( ! p2.compare_exchange_strong(a, b) );
    VERIFY( a == b );
    VERIFY( a.use_count() == 4 ); // p, p2, a, b
    VERIFY( b.use_count() == 4 );
    VERIFY( c.use_count() == 1 ); // c
    VERIFY( p.compare_exchange_weak(b, c) );
    VERIFY( b.use_count() == 3 ); // p2, a, b
    VERIFY( c.use_count() == 2 ); // p, c
    VERIFY( ! p.compare_exchange_weak(a, b) );
    VERIFY( a == c );
    VERIFY( a.use_count() == 3 ); // p, a, c
    VERIFY( b.use_count() == 2 ); // p2, b
    VERIFY( c.use_count() == 3 ); // p, a, c
    a.reset();
    b.reset();
    c.reset();
    VERIFY( counter == 0 );
  }
  VERIFY( counter == 2 );
}

int
main()
{
  test_is_lock_free();
  test_atomic_shared_ptr();
  test_wait_notify();
  test_counting();
}