proxygen
LockTraitsTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present 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 <folly/LockTraits.h>
17 #include <folly/LockTraitsBoost.h>
18 
19 #include <mutex>
20 
21 #include <folly/SharedMutex.h>
22 #include <folly/SpinLock.h>
25 
26 using namespace folly;
27 
28 static constexpr auto one_ms = std::chrono::milliseconds(1);
29 
34  public:
35  enum class CurrentLockState { UNLOCKED, SHARED, UPGRADE, UNIQUE };
36 
37  void lock() {
38  EXPECT_EQ(this->lock_state, CurrentLockState::UNLOCKED);
39  this->lock_state = CurrentLockState::UNIQUE;
40  }
41  void unlock() {
42  EXPECT_EQ(this->lock_state, CurrentLockState::UNIQUE);
43  this->lock_state = CurrentLockState::UNLOCKED;
44  }
45  void lock_shared() {
46  EXPECT_EQ(this->lock_state, CurrentLockState::UNLOCKED);
47  this->lock_state = CurrentLockState::SHARED;
48  }
49  void unlock_shared() {
50  EXPECT_EQ(this->lock_state, CurrentLockState::SHARED);
51  this->lock_state = CurrentLockState::UNLOCKED;
52  }
53  void lock_upgrade() {
54  EXPECT_EQ(this->lock_state, CurrentLockState::UNLOCKED);
55  this->lock_state = CurrentLockState::UPGRADE;
56  }
57  void unlock_upgrade() {
58  EXPECT_EQ(this->lock_state, CurrentLockState::UPGRADE);
59  this->lock_state = CurrentLockState::UNLOCKED;
60  }
61 
63  EXPECT_EQ(this->lock_state, CurrentLockState::UPGRADE);
64  this->lock_state = CurrentLockState::UNIQUE;
65  }
67  EXPECT_EQ(this->lock_state, CurrentLockState::UNIQUE);
68  this->lock_state = CurrentLockState::UPGRADE;
69  }
71  EXPECT_EQ(this->lock_state, CurrentLockState::UNIQUE);
72  this->lock_state = CurrentLockState::SHARED;
73  }
75  EXPECT_EQ(this->lock_state, CurrentLockState::UPGRADE);
76  this->lock_state = CurrentLockState::SHARED;
77  }
78 
79  template <class Rep, class Period>
80  bool try_lock_for(const std::chrono::duration<Rep, Period>&) {
81  EXPECT_EQ(this->lock_state, CurrentLockState::UNLOCKED);
82  this->lock_state = CurrentLockState::UNIQUE;
83  return true;
84  }
85 
86  template <class Rep, class Period>
87  bool try_lock_upgrade_for(const std::chrono::duration<Rep, Period>&) {
88  EXPECT_EQ(this->lock_state, CurrentLockState::UNLOCKED);
89  this->lock_state = CurrentLockState::UPGRADE;
90  return true;
91  }
92 
93  template <class Rep, class Period>
95  const std::chrono::duration<Rep, Period>&) {
96  EXPECT_EQ(this->lock_state, CurrentLockState::UPGRADE);
97  this->lock_state = CurrentLockState::UNIQUE;
98  return true;
99  }
100 
101  /*
102  * Initialize the FakeMutex with an unlocked state
103  */
104  CurrentLockState lock_state{CurrentLockState::UNLOCKED};
105 };
106 
108  using traits = LockTraits<std::mutex>;
109  static_assert(!traits::is_timed, "std:mutex is not a timed lock");
110  static_assert(!traits::is_shared, "std:mutex is not a shared lock");
111  static_assert(!traits::is_upgrade, "std::mutex is not an upgradable lock");
112 
114  traits::lock(mutex);
115  traits::unlock(mutex);
116 }
117 
119  using traits = LockTraits<SharedMutex>;
120  static_assert(traits::is_timed, "folly::SharedMutex is a timed lock");
121  static_assert(traits::is_shared, "folly::SharedMutex is a shared lock");
122  static_assert(traits::is_upgrade, "folly::SharedMutex is an upgradable lock");
123 
125  traits::lock(mutex);
126  traits::unlock(mutex);
127 
128  traits::lock_shared(mutex);
129  traits::lock_shared(mutex);
130  traits::unlock_shared(mutex);
131  traits::unlock_shared(mutex);
132 
133  traits::lock_upgrade(mutex);
134  traits::unlock_upgrade(mutex);
135 
136  // test upgrade and downgrades
137  traits::lock_upgrade(mutex);
138  traits::unlock_upgrade_and_lock(mutex);
139  bool gotLock = traits::try_lock_for(mutex, one_ms);
140  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
141  "lock after upgrading to an exclusive lock";
142  gotLock = traits::try_lock_upgrade_for(mutex, one_ms);
143  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an upgrade "
144  "lock after upgrading to an exclusive lock";
145  gotLock = traits::try_lock_shared_for(mutex, one_ms);
146  EXPECT_FALSE(gotLock) << "Should not have been able to acquire a shared "
147  "lock after upgrading to an exclusive lock";
148  traits::unlock(mutex);
149 
150  traits::lock_upgrade(mutex);
151  traits::unlock_upgrade_and_lock_shared(mutex);
152  gotLock = traits::try_lock_for(mutex, one_ms);
153  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
154  "mutex after downgrading from an upgrade to a "
155  "shared lock";
156  traits::unlock_shared(mutex);
157 
158  traits::lock(mutex);
159  gotLock = traits::try_lock_for(mutex, one_ms);
160  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
161  "lock after acquiring an exclusive lock";
162  gotLock = traits::try_lock_upgrade_for(mutex, one_ms);
163  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an upgrade "
164  "lock after acquiring an exclusive lock";
165  gotLock = traits::try_lock_shared_for(mutex, one_ms);
166  EXPECT_FALSE(gotLock) << "Should not have been able to acquire a shared "
167  "lock after acquiring an exclusive lock";
168  traits::unlock_and_lock_upgrade(mutex);
169  gotLock = traits::try_lock_for(mutex, one_ms);
170  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
171  "lock after downgrading to an upgrade lock";
172  traits::unlock_upgrade(mutex);
173 
174  traits::lock(mutex);
175  traits::unlock_and_lock_shared(mutex);
176  gotLock = traits::try_lock_for(mutex, one_ms);
177  EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
178  "lock after downgrading to a shared lock";
179  traits::unlock_shared(mutex);
180 }
181 
183  using traits = LockTraits<SpinLock>;
184  static_assert(!traits::is_timed, "folly::SpinLock is not a timed lock");
185  static_assert(!traits::is_shared, "folly::SpinLock is not a shared lock");
186  static_assert(
187  !traits::is_upgrade, "folly::SpinLock is not an upgradable lock");
188 
189  SpinLock mutex;
190  traits::lock(mutex);
191  traits::unlock(mutex);
192 }
193 
195  using traits = LockTraits<RWSpinLock>;
196  static_assert(!traits::is_timed, "folly::RWSpinLock is not a timed lock");
197  static_assert(traits::is_shared, "folly::RWSpinLock is a shared lock");
198  static_assert(traits::is_upgrade, "folly::RWSpinLock is an upgradable lock");
199 
201  traits::lock(mutex);
202  traits::unlock(mutex);
203 
204  traits::lock_shared(mutex);
205  traits::lock_shared(mutex);
206  traits::unlock_shared(mutex);
207  traits::unlock_shared(mutex);
208 }
209 
210 TEST(LockTraits, boost_mutex) {
211  using traits = LockTraits<boost::mutex>;
212  static_assert(!traits::is_timed, "boost::mutex is not a timed lock");
213  static_assert(!traits::is_shared, "boost::mutex is not a shared lock");
214  static_assert(!traits::is_upgrade, "boost::mutex is not an upgradable lock");
215 
217  traits::lock(mutex);
218  traits::unlock(mutex);
219 }
220 
221 TEST(LockTraits, boost_recursive_mutex) {
222  using traits = LockTraits<boost::recursive_mutex>;
223  static_assert(
224  !traits::is_timed, "boost::recursive_mutex is not a timed lock");
225  static_assert(
226  !traits::is_shared, "boost::recursive_mutex is not a shared lock");
227  static_assert(
228  !traits::is_upgrade, "boost::recursive_mutex is not an upgradable lock");
229 
230  boost::recursive_mutex mutex;
231  traits::lock(mutex);
232  traits::lock(mutex);
233  traits::unlock(mutex);
234  traits::unlock(mutex);
235 }
236 
237 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
238 TEST(LockTraits, timed_mutex) {
239  using traits = LockTraits<std::timed_mutex>;
240  static_assert(traits::is_timed, "std::timed_mutex is a timed lock");
241  static_assert(!traits::is_shared, "std::timed_mutex is not a shared lock");
242  static_assert(
243  !traits::is_upgrade, "std::timed_mutex is not an upgradable lock");
244 
245  std::timed_mutex mutex;
246  traits::lock(mutex);
247  bool gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
248  EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
249  << "timed_mutex a second time";
250  traits::unlock(mutex);
251 }
252 
253 TEST(LockTraits, recursive_timed_mutex) {
255  static_assert(traits::is_timed, "std::recursive_timed_mutex is a timed lock");
256  static_assert(
257  !traits::is_shared, "std::recursive_timed_mutex is not a shared lock");
258  static_assert(
259  !traits::is_upgrade,
260  "std::recursive_timed_mutex is not an upgradable lock");
261 
262  std::recursive_timed_mutex mutex;
263  traits::lock(mutex);
264  auto gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(10));
265  EXPECT_TRUE(gotLock) << "should have been able to acquire the "
266  << "recursive_timed_mutex a second time";
267  traits::unlock(mutex);
268  traits::unlock(mutex);
269 }
270 
271 TEST(LockTraits, boost_shared_mutex) {
272  using traits = LockTraits<boost::shared_mutex>;
273  static_assert(traits::is_timed, "boost::shared_mutex is a timed lock");
274  static_assert(traits::is_shared, "boost::shared_mutex is a shared lock");
275  static_assert(
276  traits::is_upgrade, "boost::shared_mutex is an upgradable lock");
277 
278  boost::shared_mutex mutex;
279  traits::lock(mutex);
280  auto gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
281  EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
282  << "shared_mutex a second time";
283  gotLock = traits::try_lock_shared_for(mutex, std::chrono::milliseconds(1));
284  EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
285  << "shared_mutex a second time";
286  traits::unlock(mutex);
287 
288  traits::lock_shared(mutex);
289  gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
290  EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
291  << "shared_mutex a second time";
292  gotLock = traits::try_lock_shared_for(mutex, std::chrono::milliseconds(10));
293  EXPECT_TRUE(gotLock) << "should have been able to acquire the "
294  << "shared_mutex a second time in shared mode";
295  traits::unlock_shared(mutex);
296  traits::unlock_shared(mutex);
297 }
298 #endif // FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
299 
304 TEST(LockTraits, LockPolicy) {
306  Mutex mutex;
307 
308  // test the lock and unlock functions
310  mutex.unlock_upgrade();
311  mutex.lock_upgrade();
313 
314  mutex.lock_upgrade();
316  mutex.unlock();
317  mutex.lock();
319 
320  mutex.lock();
322  mutex.unlock_upgrade();
323  mutex.lock_upgrade();
325 
326  mutex.lock_upgrade();
328  mutex.unlock_shared();
329  mutex.lock_shared();
331 
332  mutex.lock();
334  mutex.unlock_shared();
335  mutex.lock_shared();
337 
338  EXPECT_EQ(mutex.lock_state, Mutex::CurrentLockState::UNLOCKED);
339 }
340 
344 TEST(LockTraits, LockPolicyTimed) {
346  Mutex mutex;
347 
348  bool gotLock = LockPolicyUpgrade::try_lock_for(mutex, one_ms);
349  EXPECT_TRUE(gotLock) << "Should have been able to acquire the fake mutex";
351 
352  mutex.lock_upgrade();
354  EXPECT_TRUE(gotLock)
355  << "Should have been able to upgrade from upgrade to unique";
356  mutex.unlock();
357 
358  mutex.lock();
360  EXPECT_TRUE(gotLock) << "Should have been able to downgrade from exclusive "
361  "to upgrade";
362  mutex.unlock_upgrade();
363 
364  mutex.lock_upgrade();
366  EXPECT_TRUE(gotLock) << "Should have been able to downgrade from upgrade to "
367  "shared";
368  mutex.unlock_shared();
369 
370  mutex.lock();
372  EXPECT_TRUE(gotLock) << "Should have been able to downgrade from exclusive "
373  "to shared";
374  mutex.unlock_shared();
375 }
376 
384 TEST(LockTraits, LockPolicyCompatibilities) {
385  EXPECT_TRUE((std::is_same<
388  EXPECT_TRUE((std::is_same<
391 
392  EXPECT_TRUE((std::is_same<
395  EXPECT_TRUE((std::is_same<
398  EXPECT_TRUE((std::is_same<
401 
402  EXPECT_TRUE((std::is_same<
405  EXPECT_TRUE((std::is_same<
408 }
detail::UnlockPolicyExclusive< LockTraits > UnlockPolicy
Definition: LockTraits.h:469
static bool try_lock_for(Mutex &mutex, const std::chrono::duration< Rep, Period > &timeout)
Definition: LockTraits.h:520
static void unlock(Mutex &mutex)
Definition: LockTraits.h:381
static std::true_type lock(Mutex &mutex)
Definition: LockTraits.h:626
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
static bool try_lock_for(Mutex &mutex, const std::chrono::duration< Rep, Period > &timeout)
Definition: LockTraits.h:586
static void unlock(Mutex &mutex)
Definition: LockTraits.h:388
#define Mutex
static void unlock(Mutex &mutex)
Definition: LockTraits.h:374
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
static bool try_lock_for(Mutex &mutex, const std::chrono::duration< Rep, Period > &)
Definition: LockTraits.h:655
bool try_lock_for(const std::chrono::duration< Rep, Period > &)
static std::true_type lock(Mutex &mutex)
Definition: LockTraits.h:602
static bool try_lock_for(Mutex &mutex, const std::chrono::duration< Rep, Period > &)
Definition: LockTraits.h:607
static std::true_type lock(Mutex &mutex)
Definition: LockTraits.h:515
static bool try_lock_for(Mutex &mutex, const std::chrono::duration< Rep, Period > &)
Definition: LockTraits.h:631
static std::true_type lock(Mutex &mutex)
Definition: LockTraits.h:581
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
Definition: Synchronized.h:871
#define UPGRADE
Definition: http_parser.c:144
detail::UnlockPolicyUpgrade< LockTraits > UnlockPolicy
Definition: LockTraits.h:512
bool try_unlock_upgrade_and_lock_for(const std::chrono::duration< Rep, Period > &)
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
std::mutex mutex
detail::UnlockPolicyShared< LockTraits > UnlockPolicy
Definition: LockTraits.h:489
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
static constexpr auto one_ms
static std::true_type lock(Mutex &mutex)
Definition: LockTraits.h:650
static void std_mutex(size_t numOps, size_t numThreads)
bool try_lock_upgrade_for(const std::chrono::duration< Rep, Period > &)
TEST(SequencedExecutor, CPUThreadPoolExecutor)