proxygen
ReadMostlySharedPtrTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2015-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 /* -*- Mode: C++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
17 
18 #include <atomic>
19 #include <condition_variable>
20 #include <mutex>
21 #include <thread>
22 
23 #include <folly/Memory.h>
27 
32 
33 // send SIGALRM to test process after this many seconds
34 const unsigned int TEST_TIMEOUT = 10;
35 
37  public:
39  alarm(TEST_TIMEOUT);
40  }
41 };
42 
43 struct TestObject {
44  int value;
45  std::atomic<int>& counter;
46 
47  TestObject(int value_, std::atomic<int>& counter_)
48  : value(value_), counter(counter_) {
49  ++counter;
50  }
51 
53  assert(counter.load() > 0);
54  --counter;
55  }
56 };
57 
58 // One side calls requestAndWait(), the other side calls waitForRequest(),
59 // does something and calls completed().
60 class Coordinator {
61  public:
62  void requestAndWait() {
63  requestBaton_.post();
64  completeBaton_.wait();
65  }
66 
67  void waitForRequest() {
68  requestBaton_.wait();
69  }
70 
71  void completed() {
72  completeBaton_.post();
73  }
74 
75  private:
78 };
79 
82 
83  // Store 1.
84  std::atomic<int> cnt1{0};
85  ptr.reset(std::make_unique<TestObject>(1, cnt1));
86  EXPECT_EQ(1, cnt1.load());
87 
88  // Store 2, check that 1 is destroyed.
89  std::atomic<int> cnt2{0};
90  ptr.reset(std::make_unique<TestObject>(2, cnt2));
91  EXPECT_EQ(1, cnt2.load());
92  EXPECT_EQ(0, cnt1.load());
93 
94  // Store nullptr, check that 2 is destroyed.
95  ptr.reset(nullptr);
96  EXPECT_EQ(0, cnt2.load());
97 }
98 
100  std::atomic<int> cnt2{0};
102 
103  {
105 
106  // Check that ptr is initially nullptr.
107  EXPECT_EQ(ptr.get(), nullptr);
108 
109  std::atomic<int> cnt1{0};
110  ptr.reset(std::make_unique<TestObject>(1, cnt1));
111  EXPECT_EQ(1, cnt1.load());
112 
113  x = ptr;
114  EXPECT_EQ(1, x->value);
115 
116  ptr.reset(std::make_unique<TestObject>(2, cnt2));
117  EXPECT_EQ(1, cnt2.load());
118  EXPECT_EQ(1, cnt1.load());
119 
120  x = ptr;
121  EXPECT_EQ(2, x->value);
122  EXPECT_EQ(0, cnt1.load());
123 
124  ptr.reset(nullptr);
125  EXPECT_EQ(1, cnt2.load());
126  }
127 
128  EXPECT_EQ(1, cnt2.load());
129 
130  x.reset();
131  EXPECT_EQ(0, cnt2.load());
132 }
133 
134 TEST_F(ReadMostlySharedPtrTest, LoadsFromThreads) {
135  std::atomic<int> cnt{0};
136 
137  {
139  Coordinator loads[7];
140 
141  std::thread t1([&] {
142  loads[0].waitForRequest();
143  EXPECT_EQ(ptr.getShared(), nullptr);
144  loads[0].completed();
145 
146  loads[3].waitForRequest();
147  EXPECT_EQ(2, ptr.getShared()->value);
148  loads[3].completed();
149 
150  loads[4].waitForRequest();
151  EXPECT_EQ(4, ptr.getShared()->value);
152  loads[4].completed();
153 
154  loads[5].waitForRequest();
155  EXPECT_EQ(5, ptr.getShared()->value);
156  loads[5].completed();
157  });
158 
159  std::thread t2([&] {
160  loads[1].waitForRequest();
161  EXPECT_EQ(1, ptr.getShared()->value);
162  loads[1].completed();
163 
164  loads[2].waitForRequest();
165  EXPECT_EQ(2, ptr.getShared()->value);
166  loads[2].completed();
167 
168  loads[6].waitForRequest();
169  EXPECT_EQ(5, ptr.getShared()->value);
170  loads[6].completed();
171  });
172 
173  loads[0].requestAndWait();
174 
175  ptr.reset(std::make_unique<TestObject>(1, cnt));
176  loads[1].requestAndWait();
177 
178  ptr.reset(std::make_unique<TestObject>(2, cnt));
179  loads[2].requestAndWait();
180  loads[3].requestAndWait();
181 
182  ptr.reset(std::make_unique<TestObject>(3, cnt));
183  ptr.reset(std::make_unique<TestObject>(4, cnt));
184  loads[4].requestAndWait();
185 
186  ptr.reset(std::make_unique<TestObject>(5, cnt));
187  loads[5].requestAndWait();
188  loads[6].requestAndWait();
189 
190  EXPECT_EQ(1, cnt.load());
191 
192  t1.join();
193  t2.join();
194  }
195 
196  EXPECT_EQ(0, cnt.load());
197 }
198 
200  std::atomic<int> cnt1{0};
201  {
202  ReadMostlyMainPtr<TestObject> ptr(std::make_unique<TestObject>(1, cnt1));
203 
204  EXPECT_EQ(1, ptr.getShared()->value);
205  }
206 
207  EXPECT_EQ(0, cnt1.load());
208 }
209 
211  std::atomic<int> cnt1{0};
212  std::atomic<int> cnt2{0};
213 
215 
216  // Store 1.
217  ptr.reset(std::make_unique<TestObject>(1, cnt1));
218 
219  Coordinator c;
220 
221  std::thread t([&] {
222  // Cache the pointer for this thread.
223  ptr.getShared();
224  c.requestAndWait();
225  });
226 
227  // Wait for the thread to cache pointer.
228  c.waitForRequest();
229  EXPECT_EQ(1, cnt1.load());
230 
231  // Store 2 and check that 1 is destroyed.
232  ptr.reset(std::make_unique<TestObject>(2, cnt2));
233  EXPECT_EQ(0, cnt1.load());
234 
235  // Unblock thread.
236  c.completed();
237  t.join();
238 }
239 
240 size_t useGlobalCalls = 0;
241 
243  public:
245  DCHECK_EQ(count_.load(), 0);
246  }
247 
249  auto ret = ++count_;
250  DCHECK_GT(ret, 0);
251  return ret;
252  }
253 
255  auto ret = --count_;
256  DCHECK_GE(ret, 0);
257  return ret;
258  }
259 
261  return count_.load();
262  }
263 
264  void useGlobal() {
265  ++useGlobalCalls;
266  }
267 
268  template <typename Container>
269  static void useGlobal(const Container&) {
270  ++useGlobalCalls;
271  }
272 
273  private:
274  std::atomic<int64_t> count_{1};
275 };
276 
279  {
280  ReadMostlyMainPtr<int, TestRefCount> ptr1(std::make_shared<int>(42));
281  ReadMostlyMainPtr<int, TestRefCount> ptr2(std::make_shared<int>(42));
282  }
283 
285 
286  useGlobalCalls = 0;
287  {
288  ReadMostlyMainPtr<int, TestRefCount> ptr1(std::make_shared<int>(42));
289  ReadMostlyMainPtr<int, TestRefCount> ptr2(std::make_shared<int>(42));
290 
292  deleter.add(std::move(ptr1));
293  deleter.add(std::move(ptr2));
294  }
295 
297 }
298 
300  {
302  EXPECT_TRUE(nptr == nullptr);
303  EXPECT_TRUE(nullptr == nptr);
304  EXPECT_EQ(nptr, nullptr);
305  EXPECT_EQ(nullptr, nptr);
306  EXPECT_FALSE(nptr);
307  EXPECT_TRUE(!nptr);
308 
309  ReadMostlyMainPtr<int, TestRefCount> ptr(std::make_shared<int>(42));
310  EXPECT_FALSE(ptr == nullptr);
311  EXPECT_FALSE(nullptr == ptr);
312  EXPECT_NE(ptr, nullptr);
313  EXPECT_NE(nullptr, ptr);
314  EXPECT_FALSE(!ptr);
315  EXPECT_TRUE(ptr);
316  }
317  {
319  EXPECT_TRUE(nptr == nullptr);
320  EXPECT_TRUE(nullptr == nptr);
321  EXPECT_EQ(nptr, nullptr);
322  EXPECT_EQ(nullptr, nptr);
323  EXPECT_FALSE(nptr);
324  EXPECT_TRUE(!nptr);
325 
326  ReadMostlyMainPtr<int, TestRefCount> ptr(std::make_shared<int>(42));
327  EXPECT_FALSE(ptr == nullptr);
328  EXPECT_FALSE(nullptr == ptr);
329  EXPECT_NE(ptr, nullptr);
330  EXPECT_NE(nullptr, ptr);
331  EXPECT_FALSE(!ptr);
332  EXPECT_TRUE(ptr);
333  }
334 }
335 
337  const ReadMostlyMainPtr<int> rmmp1(std::make_shared<int>(42));
338 
340  rmmp2.reset(rmmp1.getStdShared());
341 
342  const ReadMostlySharedPtr<int> rmsp1 = rmmp1.getShared();
343  ReadMostlySharedPtr<int> rmsp2(rmsp1);
344 
345  // No conditions to check; we just wanted to ensure this compiles.
346  SUCCEED();
347 }
void * ptr
folly::Baton requestBaton_
ReadMostlySharedPtr< T, RefCount > getShared() const
static void useGlobal(const Container &)
int64_t operator--() noexcept
std::atomic< int > & counter
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const int x
std::shared_ptr< T > getStdShared() const
requires E e noexcept(noexcept(s.error(std::move(e))))
TEST_F(ReadMostlySharedPtrTest, BasicStores)
folly::Baton completeBaton_
#define SUCCEED()
Definition: gtest.h:1831
const unsigned int TEST_TIMEOUT
TestObject(int value_, std::atomic< int > &counter_)
void add(ReadMostlyMainPtr< T, RefCount > ptr) noexcept
int64_t operator*() noexcept
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
std::atomic< int > counter
int64_t operator++() noexcept
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
folly::detail::CompressionCounter * counter_
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
char c
size_t useGlobalCalls