7a6fc8103d2fa68ec1d0f4cd856f71fe8899c3a6
[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, numIters, 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() {
87   constexpr size_t kItersCount = 10000;
88
89   for (size_t i = 0; i < kItersCount; ++i) {
90     RefCount count;
91     std::mutex mutex;
92     int a{1};
93
94     std::thread t1([&]() {
95       if (++count) {
96         {
97           std::lock_guard<std::mutex> lg(mutex);
98           EXPECT_EQ(1, a);
99         }
100         --count;
101       }
102     });
103
104     std::thread t2([&]() {
105       count.useGlobal();
106       if (--count == 0) {
107         std::lock_guard<std::mutex> lg(mutex);
108         a = 0;
109       }
110     });
111
112     t1.join();
113     t2.join();
114
115     EXPECT_EQ(0, ++count);
116   }
117 }
118
119 TEST(RCURefCount, Basic) {
120   basicTest<RCURefCount>();
121 }
122
123 TEST(TLRefCount, Basic) {
124   basicTest<TLRefCount>();
125 }
126
127 TEST(RCURefCount, Stress) {
128   stressTest<TLRefCount>();
129 }
130
131 TEST(TLRefCount, Stress) {
132   stressTest<TLRefCount>();
133 }
134 }