2 * Copyright 2015-present Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 /* -*- Mode: C++; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
19 #include <condition_variable>
23 #include <folly/Memory.h>
24 #include <folly/experimental/RCURefCount.h>
25 #include <folly/experimental/ReadMostlySharedPtr.h>
26 #include <folly/portability/GTest.h>
27 #include <folly/synchronization/Baton.h>
29 using folly::ReadMostlyMainPtr;
30 using folly::ReadMostlyWeakPtr;
31 using folly::ReadMostlySharedPtr;
32 using folly::ReadMostlyMainPtrDeleter;
34 // send SIGALRM to test process after this many seconds
35 const unsigned int TEST_TIMEOUT = 10;
37 class ReadMostlySharedPtrTest : public ::testing::Test {
39 ReadMostlySharedPtrTest() {
46 std::atomic<int>& counter;
48 TestObject(int value, std::atomic<int>& counter)
49 : value(value), counter(counter) {
54 assert(counter.load() > 0);
59 // One side calls requestAndWait(), the other side calls waitForRequest(),
60 // does something and calls completed().
63 void requestAndWait() {
65 completeBaton_.wait();
68 void waitForRequest() {
69 folly::RCURegisterThread();
74 completeBaton_.post();
78 folly::Baton<> requestBaton_;
79 folly::Baton<> completeBaton_;
82 TEST_F(ReadMostlySharedPtrTest, BasicStores) {
83 ReadMostlyMainPtr<TestObject> ptr;
86 std::atomic<int> cnt1{0};
87 ptr.reset(std::make_unique<TestObject>(1, cnt1));
88 EXPECT_EQ(1, cnt1.load());
90 // Store 2, check that 1 is destroyed.
91 std::atomic<int> cnt2{0};
92 ptr.reset(std::make_unique<TestObject>(2, cnt2));
93 EXPECT_EQ(1, cnt2.load());
94 EXPECT_EQ(0, cnt1.load());
96 // Store nullptr, check that 2 is destroyed.
98 EXPECT_EQ(0, cnt2.load());
101 TEST_F(ReadMostlySharedPtrTest, BasicLoads) {
102 std::atomic<int> cnt2{0};
103 ReadMostlySharedPtr<TestObject> x;
106 ReadMostlyMainPtr<TestObject> ptr;
108 // Check that ptr is initially nullptr.
109 EXPECT_EQ(ptr.get(), nullptr);
111 std::atomic<int> cnt1{0};
112 ptr.reset(std::make_unique<TestObject>(1, cnt1));
113 EXPECT_EQ(1, cnt1.load());
116 EXPECT_EQ(1, x->value);
118 ptr.reset(std::make_unique<TestObject>(2, cnt2));
119 EXPECT_EQ(1, cnt2.load());
120 EXPECT_EQ(1, cnt1.load());
123 EXPECT_EQ(2, x->value);
124 EXPECT_EQ(0, cnt1.load());
127 EXPECT_EQ(1, cnt2.load());
130 EXPECT_EQ(1, cnt2.load());
133 EXPECT_EQ(0, cnt2.load());
136 TEST_F(ReadMostlySharedPtrTest, LoadsFromThreads) {
137 std::atomic<int> cnt{0};
140 ReadMostlyMainPtr<TestObject> ptr;
141 Coordinator loads[7];
144 loads[0].waitForRequest();
145 EXPECT_EQ(ptr.getShared(), nullptr);
146 loads[0].completed();
148 loads[3].waitForRequest();
149 EXPECT_EQ(2, ptr.getShared()->value);
150 loads[3].completed();
152 loads[4].waitForRequest();
153 EXPECT_EQ(4, ptr.getShared()->value);
154 loads[4].completed();
156 loads[5].waitForRequest();
157 EXPECT_EQ(5, ptr.getShared()->value);
158 loads[5].completed();
162 loads[1].waitForRequest();
163 EXPECT_EQ(1, ptr.getShared()->value);
164 loads[1].completed();
166 loads[2].waitForRequest();
167 EXPECT_EQ(2, ptr.getShared()->value);
168 loads[2].completed();
170 loads[6].waitForRequest();
171 EXPECT_EQ(5, ptr.getShared()->value);
172 loads[6].completed();
175 loads[0].requestAndWait();
177 ptr.reset(std::make_unique<TestObject>(1, cnt));
178 loads[1].requestAndWait();
180 ptr.reset(std::make_unique<TestObject>(2, cnt));
181 loads[2].requestAndWait();
182 loads[3].requestAndWait();
184 ptr.reset(std::make_unique<TestObject>(3, cnt));
185 ptr.reset(std::make_unique<TestObject>(4, cnt));
186 loads[4].requestAndWait();
188 ptr.reset(std::make_unique<TestObject>(5, cnt));
189 loads[5].requestAndWait();
190 loads[6].requestAndWait();
192 EXPECT_EQ(1, cnt.load());
198 EXPECT_EQ(0, cnt.load());
201 TEST_F(ReadMostlySharedPtrTest, Ctor) {
202 std::atomic<int> cnt1{0};
204 ReadMostlyMainPtr<TestObject> ptr(std::make_unique<TestObject>(1, cnt1));
206 EXPECT_EQ(1, ptr.getShared()->value);
209 EXPECT_EQ(0, cnt1.load());
212 TEST_F(ReadMostlySharedPtrTest, ClearingCache) {
213 std::atomic<int> cnt1{0};
214 std::atomic<int> cnt2{0};
216 ReadMostlyMainPtr<TestObject> ptr;
219 ptr.reset(std::make_unique<TestObject>(1, cnt1));
224 // Cache the pointer for this thread.
229 // Wait for the thread to cache pointer.
231 EXPECT_EQ(1, cnt1.load());
233 // Store 2 and check that 1 is destroyed.
234 ptr.reset(std::make_unique<TestObject>(2, cnt2));
235 EXPECT_EQ(0, cnt1.load());
242 size_t useGlobalCalls = 0;
246 ~TestRefCount() noexcept {
247 DCHECK_EQ(count_.load(), 0);
250 int64_t operator++() noexcept {
256 int64_t operator--() noexcept {
262 int64_t operator*() noexcept {
263 return count_.load();
270 template <typename Container>
271 static void useGlobal(const Container&) {
276 std::atomic<int64_t> count_{1};
279 TEST_F(ReadMostlySharedPtrTest, ReadMostlyMainPtrDeleter) {
280 EXPECT_EQ(0, useGlobalCalls);
282 ReadMostlyMainPtr<int, TestRefCount> ptr1(std::make_shared<int>(42));
283 ReadMostlyMainPtr<int, TestRefCount> ptr2(std::make_shared<int>(42));
286 EXPECT_EQ(4, useGlobalCalls);
290 ReadMostlyMainPtr<int, TestRefCount> ptr1(std::make_shared<int>(42));
291 ReadMostlyMainPtr<int, TestRefCount> ptr2(std::make_shared<int>(42));
293 ReadMostlyMainPtrDeleter<TestRefCount> deleter;
294 deleter.add(std::move(ptr1));
295 deleter.add(std::move(ptr2));
298 EXPECT_EQ(1, useGlobalCalls);
301 TEST_F(ReadMostlySharedPtrTest, nullptr) {
303 ReadMostlyMainPtr<int, TestRefCount> nptr;
304 EXPECT_TRUE(nptr == nullptr);
305 EXPECT_TRUE(nullptr == nptr);
306 EXPECT_EQ(nptr, nullptr);
307 EXPECT_EQ(nullptr, nptr);
311 ReadMostlyMainPtr<int, TestRefCount> ptr(std::make_shared<int>(42));
312 EXPECT_FALSE(ptr == nullptr);
313 EXPECT_FALSE(nullptr == ptr);
314 EXPECT_NE(ptr, nullptr);
315 EXPECT_NE(nullptr, ptr);
320 ReadMostlySharedPtr<int, TestRefCount> nptr;
321 EXPECT_TRUE(nptr == nullptr);
322 EXPECT_TRUE(nullptr == nptr);
323 EXPECT_EQ(nptr, nullptr);
324 EXPECT_EQ(nullptr, nptr);
328 ReadMostlyMainPtr<int, TestRefCount> ptr(std::make_shared<int>(42));
329 EXPECT_FALSE(ptr == nullptr);
330 EXPECT_FALSE(nullptr == ptr);
331 EXPECT_NE(ptr, nullptr);
332 EXPECT_NE(nullptr, ptr);
338 TEST_F(ReadMostlySharedPtrTest, getStdShared) {
339 const ReadMostlyMainPtr<int> rmmp1(std::make_shared<int>(42));
341 ReadMostlyMainPtr<int> rmmp2;
342 rmmp2.reset(rmmp1.getStdShared());
344 const ReadMostlySharedPtr<int> rmsp1 = rmmp1.getShared();
345 ReadMostlySharedPtr<int> rmsp2(rmsp1);
347 // No conditions to check; we just wanted to ensure this compiles.