Use the GTest portability headers
[folly.git] / folly / experimental / test / ReadMostlySharedPtrTest.cpp
1 /*
2  * Copyright 2016 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 <thread>
20 #include <mutex>
21 #include <folly/Memory.h>
22 #include <condition_variable>
23
24 #include <folly/Baton.h>
25 #include <folly/experimental/RCURefCount.h>
26 #include <folly/experimental/ReadMostlySharedPtr.h>
27 #include <folly/portability/GTest.h>
28
29 using folly::ReadMostlyMainPtr;
30 using folly::ReadMostlyWeakPtr;
31 using folly::ReadMostlySharedPtr;
32 using folly::ReadMostlyMainPtrDeleter;
33
34 // send SIGALRM to test process after this many seconds
35 const unsigned int TEST_TIMEOUT = 10;
36
37 class ReadMostlySharedPtrTest : public ::testing::Test {
38  public:
39   ReadMostlySharedPtrTest() {
40     alarm(TEST_TIMEOUT);
41   }
42 };
43
44 struct TestObject {
45   int value;
46   std::atomic<int>& counter;
47
48   TestObject(int value, std::atomic<int>& counter)
49       : value(value), counter(counter) {
50     ++counter;
51   }
52
53   ~TestObject() {
54     assert(counter.load() > 0);
55     --counter;
56   }
57 };
58
59 // One side calls requestAndWait(), the other side calls waitForRequest(),
60 // does something and calls completed().
61 class Coordinator {
62  public:
63   void requestAndWait() {
64     requestBaton_.post();
65     completeBaton_.wait();
66   }
67
68   void waitForRequest() {
69     folly::RCURegisterThread();
70     requestBaton_.wait();
71   }
72
73   void completed() {
74     completeBaton_.post();
75   }
76
77  private:
78   folly::Baton<> requestBaton_;
79   folly::Baton<> completeBaton_;
80 };
81
82 TEST_F(ReadMostlySharedPtrTest, BasicStores) {
83   ReadMostlyMainPtr<TestObject> ptr;
84
85   // Store 1.
86   std::atomic<int> cnt1{0};
87   ptr.reset(folly::make_unique<TestObject>(1, cnt1));
88   EXPECT_EQ(1, cnt1.load());
89
90   // Store 2, check that 1 is destroyed.
91   std::atomic<int> cnt2{0};
92   ptr.reset(folly::make_unique<TestObject>(2, cnt2));
93   EXPECT_EQ(1, cnt2.load());
94   EXPECT_EQ(0, cnt1.load());
95
96   // Store nullptr, check that 2 is destroyed.
97   ptr.reset(nullptr);
98   EXPECT_EQ(0, cnt2.load());
99 }
100
101 TEST_F(ReadMostlySharedPtrTest, BasicLoads) {
102   std::atomic<int> cnt2{0};
103   ReadMostlySharedPtr<TestObject> x;
104
105   {
106     ReadMostlyMainPtr<TestObject> ptr;
107
108     // Check that ptr is initially nullptr.
109     EXPECT_EQ(ptr.get(), nullptr);
110
111     std::atomic<int> cnt1{0};
112     ptr.reset(folly::make_unique<TestObject>(1, cnt1));
113     EXPECT_EQ(1, cnt1.load());
114
115     x = ptr;
116     EXPECT_EQ(1, x->value);
117
118     ptr.reset(folly::make_unique<TestObject>(2, cnt2));
119     EXPECT_EQ(1, cnt2.load());
120     EXPECT_EQ(1, cnt1.load());
121
122     x = ptr;
123     EXPECT_EQ(2, x->value);
124     EXPECT_EQ(0, cnt1.load());
125
126     ptr.reset(nullptr);
127     EXPECT_EQ(1, cnt2.load());
128   }
129
130   EXPECT_EQ(1, cnt2.load());
131
132   x.reset();
133   EXPECT_EQ(0, cnt2.load());
134 }
135
136 TEST_F(ReadMostlySharedPtrTest, LoadsFromThreads) {
137   std::atomic<int> cnt{0};
138
139   {
140     ReadMostlyMainPtr<TestObject> ptr;
141     Coordinator loads[7];
142
143     std::thread t1([&] {
144       loads[0].waitForRequest();
145       EXPECT_EQ(ptr.getShared(), nullptr);
146       loads[0].completed();
147
148       loads[3].waitForRequest();
149       EXPECT_EQ(2, ptr.getShared()->value);
150       loads[3].completed();
151
152       loads[4].waitForRequest();
153       EXPECT_EQ(4, ptr.getShared()->value);
154       loads[4].completed();
155
156       loads[5].waitForRequest();
157       EXPECT_EQ(5, ptr.getShared()->value);
158       loads[5].completed();
159     });
160
161     std::thread t2([&] {
162       loads[1].waitForRequest();
163       EXPECT_EQ(1, ptr.getShared()->value);
164       loads[1].completed();
165
166       loads[2].waitForRequest();
167       EXPECT_EQ(2, ptr.getShared()->value);
168       loads[2].completed();
169
170       loads[6].waitForRequest();
171       EXPECT_EQ(5, ptr.getShared()->value);
172       loads[6].completed();
173     });
174
175     loads[0].requestAndWait();
176
177     ptr.reset(folly::make_unique<TestObject>(1, cnt));
178     loads[1].requestAndWait();
179
180     ptr.reset(folly::make_unique<TestObject>(2, cnt));
181     loads[2].requestAndWait();
182     loads[3].requestAndWait();
183
184     ptr.reset(folly::make_unique<TestObject>(3, cnt));
185     ptr.reset(folly::make_unique<TestObject>(4, cnt));
186     loads[4].requestAndWait();
187
188     ptr.reset(folly::make_unique<TestObject>(5, cnt));
189     loads[5].requestAndWait();
190     loads[6].requestAndWait();
191
192     EXPECT_EQ(1, cnt.load());
193
194     t1.join();
195     t2.join();
196   }
197
198   EXPECT_EQ(0, cnt.load());
199 }
200
201 TEST_F(ReadMostlySharedPtrTest, Ctor) {
202   std::atomic<int> cnt1{0};
203   {
204     ReadMostlyMainPtr<TestObject> ptr(
205       folly::make_unique<TestObject>(1, cnt1));
206
207     EXPECT_EQ(1, ptr.getShared()->value);
208   }
209
210   EXPECT_EQ(0, cnt1.load());
211 }
212
213 TEST_F(ReadMostlySharedPtrTest, ClearingCache) {
214   ReadMostlyMainPtr<TestObject> ptr;
215
216   // Store 1.
217   std::atomic<int> cnt1{0};
218   ptr.reset(folly::make_unique<TestObject>(1, cnt1));
219
220   Coordinator c;
221
222   std::thread t([&] {
223     // Cache the pointer for this thread.
224     ptr.getShared();
225     c.requestAndWait();
226   });
227
228   // Wait for the thread to cache pointer.
229   c.waitForRequest();
230   EXPECT_EQ(1, cnt1.load());
231
232   // Store 2 and check that 1 is destroyed.
233   std::atomic<int> cnt2{0};
234   ptr.reset(folly::make_unique<TestObject>(2, cnt2));
235   EXPECT_EQ(0, cnt1.load());
236
237   // Unblock thread.
238   c.completed();
239   t.join();
240 }
241
242 size_t useGlobalCalls = 0;
243
244 class TestRefCount {
245  public:
246   ~TestRefCount() noexcept {
247     DCHECK_EQ(count_.load(), 0);
248   }
249
250   int64_t operator++() noexcept {
251     auto ret = ++count_;
252     DCHECK_GT(ret, 0);
253     return ret;
254   }
255
256   int64_t operator--() noexcept {
257     auto ret = --count_;
258     DCHECK_GE(ret, 0);
259     return ret;
260   }
261
262   int64_t operator*() noexcept {
263     return count_.load();
264   }
265
266   void useGlobal() {
267     ++useGlobalCalls;
268   }
269
270   template <typename Container>
271   static void useGlobal(const Container&) {
272     ++useGlobalCalls;
273   }
274
275  private:
276   std::atomic<int64_t> count_{1};
277 };
278
279 TEST_F(ReadMostlySharedPtrTest, ReadMostlyMainPtrDeleter) {
280   EXPECT_EQ(0, useGlobalCalls);
281   {
282     ReadMostlyMainPtr<int, TestRefCount> ptr1(std::make_shared<int>(42));
283     ReadMostlyMainPtr<int, TestRefCount> ptr2(std::make_shared<int>(42));
284   }
285
286   EXPECT_EQ(4, useGlobalCalls);
287
288   useGlobalCalls = 0;
289   {
290     ReadMostlyMainPtr<int, TestRefCount> ptr1(std::make_shared<int>(42));
291     ReadMostlyMainPtr<int, TestRefCount> ptr2(std::make_shared<int>(42));
292
293     ReadMostlyMainPtrDeleter<TestRefCount> deleter;
294     deleter.add(std::move(ptr1));
295     deleter.add(std::move(ptr2));
296   }
297
298   EXPECT_EQ(1, useGlobalCalls);
299 }