1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
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
17 #include <folly/Executor.h>
18
19 #include <atomic>
20
21 #include <folly/lang/Keep.h>
22 #include <folly/portability/GTest.h>
23
check_executor_invoke_catching_exns(void (* f)())24 extern "C" FOLLY_KEEP void check_executor_invoke_catching_exns(void (*f)()) {
25 folly::Executor::invokeCatchingExns("check", f);
26 }
27
28 namespace folly {
29
30 class KeepAliveTestExecutor : public Executor {
31 public:
add(Func)32 void add(Func) override {
33 // this executor does nothing
34 }
35
keepAliveAcquire()36 bool keepAliveAcquire() noexcept override {
37 ++refCount;
38 return true;
39 }
40
keepAliveRelease()41 void keepAliveRelease() noexcept override { --refCount; }
42
43 std::atomic<int> refCount{0};
44 };
45
TEST(ExecutorTest,KeepAliveBasic)46 TEST(ExecutorTest, KeepAliveBasic) {
47 KeepAliveTestExecutor exec;
48
49 {
50 auto ka = getKeepAliveToken(exec);
51 EXPECT_TRUE(ka);
52 EXPECT_EQ(&exec, ka.get());
53 EXPECT_EQ(1, exec.refCount);
54 }
55
56 EXPECT_EQ(0, exec.refCount);
57 }
58
TEST(ExecutorTest,KeepAliveMoveConstructor)59 TEST(ExecutorTest, KeepAliveMoveConstructor) {
60 KeepAliveTestExecutor exec;
61
62 {
63 auto ka = getKeepAliveToken(exec);
64 EXPECT_TRUE(ka);
65 EXPECT_EQ(&exec, ka.get());
66 EXPECT_EQ(1, exec.refCount);
67
68 // member move constructor
69 Executor::KeepAlive<KeepAliveTestExecutor> ka2(std::move(ka));
70 EXPECT_FALSE(ka);
71 EXPECT_TRUE(ka2);
72 EXPECT_EQ(&exec, ka2.get());
73 EXPECT_EQ(1, exec.refCount);
74
75 // template move constructor
76 Executor::KeepAlive<Executor> ka3(std::move(ka2));
77 EXPECT_FALSE(ka2);
78 EXPECT_TRUE(ka3);
79 EXPECT_EQ(&exec, ka3.get());
80 EXPECT_EQ(1, exec.refCount);
81 }
82
83 EXPECT_EQ(0, exec.refCount);
84 }
85
TEST(ExecutorTest,KeepAliveCopyConstructor)86 TEST(ExecutorTest, KeepAliveCopyConstructor) {
87 KeepAliveTestExecutor exec;
88
89 {
90 auto ka = getKeepAliveToken(exec);
91 EXPECT_TRUE(ka);
92 EXPECT_EQ(&exec, ka.get());
93 EXPECT_EQ(1, exec.refCount);
94
95 // member copy constructor
96 Executor::KeepAlive<KeepAliveTestExecutor> ka2(ka);
97 EXPECT_TRUE(ka);
98 EXPECT_TRUE(ka2);
99 EXPECT_EQ(&exec, ka2.get());
100 EXPECT_EQ(2, exec.refCount);
101
102 // template copy constructor
103 Executor::KeepAlive<Executor> ka3(ka);
104 EXPECT_TRUE(ka);
105 EXPECT_TRUE(ka3);
106 EXPECT_EQ(&exec, ka3.get());
107 EXPECT_EQ(3, exec.refCount);
108 }
109
110 EXPECT_EQ(0, exec.refCount);
111 }
112
TEST(ExecutorTest,KeepAliveImplicitConstructorFromRawPtr)113 TEST(ExecutorTest, KeepAliveImplicitConstructorFromRawPtr) {
114 KeepAliveTestExecutor exec;
115
116 {
117 auto myFunc = [&exec](Executor::KeepAlive<> /*ka*/) mutable {
118 EXPECT_EQ(1, exec.refCount);
119 };
120 myFunc(&exec);
121 }
122
123 EXPECT_EQ(0, exec.refCount);
124 }
125
TEST(ExecutorTest,KeepAliveMoveAssignment)126 TEST(ExecutorTest, KeepAliveMoveAssignment) {
127 KeepAliveTestExecutor exec;
128
129 {
130 auto ka = getKeepAliveToken(exec);
131 EXPECT_TRUE(ka);
132 EXPECT_EQ(&exec, ka.get());
133 EXPECT_EQ(1, exec.refCount);
134
135 Executor::KeepAlive<> ka2;
136 ka2 = std::move(ka);
137 EXPECT_FALSE(ka);
138 EXPECT_TRUE(ka2);
139 EXPECT_EQ(&exec, ka2.get());
140 EXPECT_EQ(1, exec.refCount);
141 }
142
143 EXPECT_EQ(0, exec.refCount);
144 }
145
TEST(ExecutorTest,KeepAliveCopyAssignment)146 TEST(ExecutorTest, KeepAliveCopyAssignment) {
147 KeepAliveTestExecutor exec;
148
149 {
150 auto ka = getKeepAliveToken(exec);
151 EXPECT_TRUE(ka);
152 EXPECT_EQ(&exec, ka.get());
153 EXPECT_EQ(1, exec.refCount);
154
155 decltype(ka) ka2;
156 ka2 = ka;
157 EXPECT_TRUE(ka);
158 EXPECT_TRUE(ka2);
159 EXPECT_EQ(&exec, ka2.get());
160 EXPECT_EQ(2, exec.refCount);
161 }
162
163 EXPECT_EQ(0, exec.refCount);
164 }
165
TEST(ExecutorTest,KeepAliveConvert)166 TEST(ExecutorTest, KeepAliveConvert) {
167 KeepAliveTestExecutor exec;
168
169 {
170 auto ka = getKeepAliveToken(exec);
171 EXPECT_TRUE(ka);
172 EXPECT_EQ(&exec, ka.get());
173 EXPECT_EQ(1, exec.refCount);
174
175 Executor::KeepAlive<Executor> ka2 = std::move(ka); // conversion
176 EXPECT_FALSE(ka);
177 EXPECT_TRUE(ka2);
178 EXPECT_EQ(&exec, ka2.get());
179 EXPECT_EQ(1, exec.refCount);
180 }
181
182 EXPECT_EQ(0, exec.refCount);
183 }
184
TEST(ExecutorTest,KeepAliveCopy)185 TEST(ExecutorTest, KeepAliveCopy) {
186 KeepAliveTestExecutor exec;
187
188 {
189 auto ka = getKeepAliveToken(exec);
190 EXPECT_TRUE(ka);
191 EXPECT_EQ(&exec, ka.get());
192 EXPECT_EQ(1, exec.refCount);
193
194 auto ka2 = ka.copy();
195 EXPECT_TRUE(ka);
196 EXPECT_TRUE(ka2);
197 EXPECT_EQ(&exec, ka2.get());
198 EXPECT_EQ(2, exec.refCount);
199 }
200
201 EXPECT_EQ(0, exec.refCount);
202 }
203
TEST(ExecutorTest,GetKeepAliveTokenFromToken)204 TEST(ExecutorTest, GetKeepAliveTokenFromToken) {
205 KeepAliveTestExecutor exec;
206
207 {
208 auto ka = getKeepAliveToken(exec);
209 EXPECT_TRUE(ka);
210 EXPECT_EQ(&exec, ka.get());
211 EXPECT_EQ(1, exec.refCount);
212
213 auto ka2 = getKeepAliveToken(ka);
214 EXPECT_TRUE(ka);
215 EXPECT_TRUE(ka2);
216 EXPECT_EQ(&exec, ka2.get());
217 EXPECT_EQ(2, exec.refCount);
218 }
219
220 EXPECT_EQ(0, exec.refCount);
221 }
222
TEST(ExecutorTest,CopyExpired)223 TEST(ExecutorTest, CopyExpired) {
224 struct Ex : Executor {
225 void add(Func) override {}
226 };
227
228 Ex* ptr = nullptr;
229 Executor::KeepAlive<Ex> ka;
230
231 {
232 auto ex = std::make_unique<Ex>();
233 ptr = ex.get();
234 ka = getKeepAliveToken(ptr);
235 }
236
237 ka = ka.copy(); // if copy() doesn't check dummy, expect segfault
238
239 EXPECT_EQ(ptr, ka.get());
240 }
241
242 } // namespace folly
243