2 * Copyright 2016 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 #include <folly/LockTraits.h>
17 #include <folly/LockTraitsBoost.h>
19 #include <gtest/gtest.h>
22 #include <folly/RWSpinLock.h>
23 #include <folly/SharedMutex.h>
24 #include <folly/SpinLock.h>
26 using namespace folly;
28 static constexpr auto one_ms = std::chrono::milliseconds(1);
30 TEST(LockTraits, std_mutex) {
31 using traits = LockTraits<std::mutex>;
32 static_assert(!traits::is_timed, "std:mutex is not a timed lock");
33 static_assert(!traits::is_shared, "std:mutex is not a shared lock");
34 static_assert(!traits::is_upgrade, "std::mutex is not an upgradable lock");
38 traits::unlock(mutex);
40 lock_shared_or_unique(mutex);
41 unlock_shared_or_unique(mutex);
44 TEST(LockTraits, SharedMutex) {
45 using traits = LockTraits<SharedMutex>;
46 static_assert(traits::is_timed, "folly::SharedMutex is a timed lock");
47 static_assert(traits::is_shared, "folly::SharedMutex is a shared lock");
48 static_assert(traits::is_upgrade, "folly::SharedMutex is an upgradable lock");
52 traits::unlock(mutex);
54 traits::lock_shared(mutex);
55 traits::lock_shared(mutex);
56 traits::unlock_shared(mutex);
57 traits::unlock_shared(mutex);
59 lock_shared_or_unique(mutex);
60 lock_shared_or_unique(mutex);
61 unlock_shared_or_unique(mutex);
62 unlock_shared_or_unique(mutex);
64 traits::lock_upgrade(mutex);
65 traits::unlock_upgrade(mutex);
67 // test upgrade and downgrades
68 traits::lock_upgrade(mutex);
69 traits::unlock_upgrade_and_lock(mutex);
70 bool gotLock = traits::try_lock_for(mutex, one_ms);
71 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
72 "lock after upgrading to an exclusive lock";
73 gotLock = traits::try_lock_upgrade_for(mutex, one_ms);
74 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an upgrade "
75 "lock after upgrading to an exclusive lock";
76 gotLock = traits::try_lock_shared_for(mutex, one_ms);
77 EXPECT_FALSE(gotLock) << "Should not have been able to acquire a shared "
78 "lock after upgrading to an exclusive lock";
79 traits::unlock(mutex);
81 traits::lock_upgrade(mutex);
82 traits::unlock_upgrade_and_lock_shared(mutex);
83 gotLock = traits::try_lock_for(mutex, one_ms);
84 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
85 "mutex after downgrading from an upgrade to a "
87 traits::unlock_shared(mutex);
90 gotLock = traits::try_lock_for(mutex, one_ms);
91 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
92 "lock after acquiring an exclusive lock";
93 gotLock = traits::try_lock_upgrade_for(mutex, one_ms);
94 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an upgrade "
95 "lock after acquiring an exclusive lock";
96 gotLock = traits::try_lock_shared_for(mutex, one_ms);
97 EXPECT_FALSE(gotLock) << "Should not have been able to acquire a shared "
98 "lock after acquiring an exclusive lock";
99 traits::unlock_and_lock_upgrade(mutex);
100 gotLock = traits::try_lock_for(mutex, one_ms);
101 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
102 "lock after downgrading to an upgrade lock";
103 traits::unlock_upgrade(mutex);
106 traits::unlock_and_lock_shared(mutex);
107 gotLock = traits::try_lock_for(mutex, one_ms);
108 EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
109 "lock after downgrading to a shared lock";
110 traits::unlock_shared(mutex);
113 TEST(LockTraits, SpinLock) {
114 using traits = LockTraits<SpinLock>;
115 static_assert(!traits::is_timed, "folly::SpinLock is not a timed lock");
116 static_assert(!traits::is_shared, "folly::SpinLock is not a shared lock");
118 !traits::is_upgrade, "folly::SpinLock is not an upgradable lock");
122 traits::unlock(mutex);
124 lock_shared_or_unique(mutex);
125 unlock_shared_or_unique(mutex);
128 TEST(LockTraits, RWSpinLock) {
129 using traits = LockTraits<RWSpinLock>;
130 static_assert(!traits::is_timed, "folly::RWSpinLock is not a timed lock");
131 static_assert(traits::is_shared, "folly::RWSpinLock is a shared lock");
132 static_assert(traits::is_upgrade, "folly::RWSpinLock is an upgradable lock");
136 traits::unlock(mutex);
138 traits::lock_shared(mutex);
139 traits::lock_shared(mutex);
140 traits::unlock_shared(mutex);
141 traits::unlock_shared(mutex);
143 lock_shared_or_unique(mutex);
144 lock_shared_or_unique(mutex);
145 unlock_shared_or_unique(mutex);
146 unlock_shared_or_unique(mutex);
149 TEST(LockTraits, boost_mutex) {
150 using traits = LockTraits<boost::mutex>;
151 static_assert(!traits::is_timed, "boost::mutex is not a timed lock");
152 static_assert(!traits::is_shared, "boost::mutex is not a shared lock");
153 static_assert(!traits::is_upgrade, "boost::mutex is not an upgradable lock");
157 traits::unlock(mutex);
159 lock_shared_or_unique(mutex);
160 unlock_shared_or_unique(mutex);
163 TEST(LockTraits, boost_recursive_mutex) {
164 using traits = LockTraits<boost::recursive_mutex>;
166 !traits::is_timed, "boost::recursive_mutex is not a timed lock");
168 !traits::is_shared, "boost::recursive_mutex is not a shared lock");
170 !traits::is_upgrade, "boost::recursive_mutex is not an upgradable lock");
172 boost::recursive_mutex mutex;
175 traits::unlock(mutex);
176 traits::unlock(mutex);
178 lock_shared_or_unique(mutex);
179 lock_shared_or_unique(mutex);
180 unlock_shared_or_unique(mutex);
181 unlock_shared_or_unique(mutex);
184 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
185 TEST(LockTraits, timed_mutex) {
186 using traits = LockTraits<std::timed_mutex>;
187 static_assert(traits::is_timed, "std::timed_mutex is a timed lock");
188 static_assert(!traits::is_shared, "std::timed_mutex is not a shared lock");
190 !traits::is_upgrade, "std::timed_mutex is not an upgradable lock");
192 std::timed_mutex mutex;
194 bool gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
195 EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
196 << "timed_mutex a second time";
197 traits::unlock(mutex);
199 lock_shared_or_unique(mutex);
200 gotLock = try_lock_shared_or_unique_for(mutex, std::chrono::milliseconds(1));
201 EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
202 << "timed_mutex a second time";
203 unlock_shared_or_unique(mutex);
206 TEST(LockTraits, recursive_timed_mutex) {
207 using traits = LockTraits<std::recursive_timed_mutex>;
208 static_assert(traits::is_timed, "std::recursive_timed_mutex is a timed lock");
210 !traits::is_shared, "std::recursive_timed_mutex is not a shared lock");
213 "std::recursive_timed_mutex is not an upgradable lock");
215 std::recursive_timed_mutex mutex;
217 auto gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(10));
218 EXPECT_TRUE(gotLock) << "should have been able to acquire the "
219 << "recursive_timed_mutex a second time";
220 traits::unlock(mutex);
221 traits::unlock(mutex);
223 lock_shared_or_unique(mutex);
224 gotLock = try_lock_shared_or_unique_for(mutex, std::chrono::milliseconds(10));
225 EXPECT_TRUE(gotLock) << "should have been able to acquire the "
226 << "recursive_timed_mutex a second time";
227 unlock_shared_or_unique(mutex);
228 unlock_shared_or_unique(mutex);
231 TEST(LockTraits, boost_shared_mutex) {
232 using traits = LockTraits<boost::shared_mutex>;
233 static_assert(traits::is_timed, "boost::shared_mutex is a timed lock");
234 static_assert(traits::is_shared, "boost::shared_mutex is a shared lock");
236 traits::is_upgrade, "boost::shared_mutex is an upgradable lock");
238 boost::shared_mutex mutex;
240 auto gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
241 EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
242 << "shared_mutex a second time";
243 gotLock = traits::try_lock_shared_for(mutex, std::chrono::milliseconds(1));
244 EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
245 << "shared_mutex a second time";
246 traits::unlock(mutex);
248 traits::lock_shared(mutex);
249 gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
250 EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
251 << "shared_mutex a second time";
252 gotLock = traits::try_lock_shared_for(mutex, std::chrono::milliseconds(10));
253 EXPECT_TRUE(gotLock) << "should have been able to acquire the "
254 << "shared_mutex a second time in shared mode";
255 traits::unlock_shared(mutex);
256 traits::unlock_shared(mutex);
258 lock_shared_or_unique(mutex);
259 gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
260 EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
261 << "shared_mutex a second time";
262 gotLock = try_lock_shared_or_unique_for(mutex, std::chrono::milliseconds(10));
263 EXPECT_TRUE(gotLock) << "should have been able to acquire the "
264 << "shared_mutex a second time in shared mode";
265 unlock_shared_or_unique(mutex);
266 unlock_shared_or_unique(mutex);
268 #endif // FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES