65c338a52a27beca1d68942c5477a615a882e58f
[folly.git] / folly / experimental / test / RefCountTest.cpp
1 /*
2  * Copyright 2017 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 #include <thread>
17
18 #include <folly/Baton.h>
19 #include <folly/experimental/RCURefCount.h>
20 #include <folly/experimental/TLRefCount.h>
21 #include <folly/portability/GTest.h>
22
23 namespace folly {
24
25 template <typename RefCount>
26 void basicTest() {
27   constexpr size_t numIters = 100000;
28   constexpr size_t numThreads = 10;
29
30   size_t got0 = 0;
31
32   RefCount count;
33
34   folly::Baton<> b;
35
36   std::vector<std::thread> ts;
37   folly::Baton<> threadBatons[numThreads];
38   for (size_t t = 0; t < numThreads; ++t) {
39     ts.emplace_back([&count, &b, &got0, t, &threadBatons] {
40       for (size_t i = 0; i < numIters; ++i) {
41         auto ret = ++count;
42
43         EXPECT_TRUE(ret > 1);
44         if (i == 0) {
45           threadBatons[t].post();
46         }
47       }
48
49       if (t == 0) {
50         b.post();
51       }
52
53       for (size_t i = 0; i < numIters; ++i) {
54         auto ret = --count;
55
56         if (ret == 0) {
57           ++got0;
58           EXPECT_EQ(numIters - 1, i);
59         }
60       }
61     });
62   }
63
64   for (size_t t = 0; t < numThreads; ++t) {
65     threadBatons[t].wait();
66   }
67
68   b.wait();
69
70   count.useGlobal();
71   if (--count == 0) {
72     ++got0;
73   }
74
75   for (auto& t: ts) {
76     t.join();
77   }
78
79   EXPECT_EQ(1, got0);
80
81   EXPECT_EQ(0, ++count);
82   EXPECT_EQ(0, ++count);
83 }
84
85 template <typename RefCount>
86 void stressTest(size_t itersCount) {
87   for (size_t i = 0; i < itersCount; ++i) {
88     RefCount count;
89     std::mutex mutex;
90     int a{1};
91
92     std::thread t1([&]() {
93       if (++count) {
94         {
95           std::lock_guard<std::mutex> lg(mutex);
96           EXPECT_EQ(1, a);
97         }
98         --count;
99       }
100     });
101
102     std::thread t2([&]() {
103       count.useGlobal();
104       if (--count == 0) {
105         std::lock_guard<std::mutex> lg(mutex);
106         a = 0;
107       }
108     });
109
110     t1.join();
111     t2.join();
112
113     EXPECT_EQ(0, ++count);
114   }
115 }
116
117 TEST(RCURefCount, Basic) {
118   basicTest<RCURefCount>();
119 }
120
121 TEST(TLRefCount, Basic) {
122   basicTest<TLRefCount>();
123 }
124
125 TEST(RCURefCount, Stress) {
126   stressTest<RCURefCount>(100000);
127 }
128
129 TEST(TLRefCount, Stress) {
130   // This is absurdly slow, so we can't
131   // do it that many times.
132   stressTest<TLRefCount>(500);
133 }
134 }