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