Commit 84f24236 authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook Github Bot 6

Adding support for upgradable mutexes to LockTraits

Summary:
This diff adds support for upgradable mutexes to the LockTraits
abstraction used by folly::Synchronized

Reviewed By: yfeldblum

Differential Revision: D3645453

fbshipit-source-id: 30f16eb3fbebc687a4136256f1103962c0e4c465
parent b22e53e0
This diff is collapsed.
...@@ -44,7 +44,7 @@ boost::chrono::duration<Rep, boost::ratio<Num, Denom>> toBoostDuration( ...@@ -44,7 +44,7 @@ boost::chrono::duration<Rep, boost::ratio<Num, Denom>> toBoostDuration(
*/ */
template <> template <>
struct LockTraits<boost::shared_mutex> struct LockTraits<boost::shared_mutex>
: public folly::detail::LockTraitsSharedBase<boost::shared_mutex> { : public LockTraitsBase<boost::shared_mutex> {
static constexpr bool is_shared = true; static constexpr bool is_shared = true;
static constexpr bool is_timed = true; static constexpr bool is_timed = true;
...@@ -68,7 +68,7 @@ struct LockTraits<boost::shared_mutex> ...@@ -68,7 +68,7 @@ struct LockTraits<boost::shared_mutex>
*/ */
template <> template <>
struct LockTraits<boost::timed_mutex> struct LockTraits<boost::timed_mutex>
: public folly::detail::LockTraitsUniqueBase<boost::timed_mutex> { : public LockTraitsBase<boost::timed_mutex> {
static constexpr bool is_shared = false; static constexpr bool is_shared = false;
static constexpr bool is_timed = true; static constexpr bool is_timed = true;
...@@ -85,7 +85,7 @@ struct LockTraits<boost::timed_mutex> ...@@ -85,7 +85,7 @@ struct LockTraits<boost::timed_mutex>
*/ */
template <> template <>
struct LockTraits<boost::recursive_timed_mutex> struct LockTraits<boost::recursive_timed_mutex>
: public folly::detail::LockTraitsUniqueBase<boost::recursive_timed_mutex> { : public LockTraitsBase<boost::recursive_timed_mutex> {
static constexpr bool is_shared = false; static constexpr bool is_shared = false;
static constexpr bool is_timed = true; static constexpr bool is_timed = true;
......
...@@ -25,10 +25,13 @@ ...@@ -25,10 +25,13 @@
using namespace folly; using namespace folly;
static constexpr auto one_ms = std::chrono::milliseconds(1);
TEST(LockTraits, std_mutex) { TEST(LockTraits, std_mutex) {
using traits = LockTraits<std::mutex>; using traits = LockTraits<std::mutex>;
static_assert(!traits::is_timed, "std:mutex is not a timed lock"); static_assert(!traits::is_timed, "std:mutex is not a timed lock");
static_assert(!traits::is_shared, "std:mutex is not a shared lock"); static_assert(!traits::is_shared, "std:mutex is not a shared lock");
static_assert(!traits::is_upgrade, "std::mutex is not an upgradable lock");
std::mutex mutex; std::mutex mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -40,8 +43,9 @@ TEST(LockTraits, std_mutex) { ...@@ -40,8 +43,9 @@ TEST(LockTraits, std_mutex) {
TEST(LockTraits, SharedMutex) { TEST(LockTraits, SharedMutex) {
using traits = LockTraits<SharedMutex>; using traits = LockTraits<SharedMutex>;
static_assert(traits::is_timed, "SharedMutex is a timed lock"); static_assert(traits::is_timed, "folly::SharedMutex is a timed lock");
static_assert(traits::is_shared, "SharedMutex is a shared lock"); static_assert(traits::is_shared, "folly::SharedMutex is a shared lock");
static_assert(traits::is_upgrade, "folly::SharedMutex is an upgradable lock");
SharedMutex mutex; SharedMutex mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -56,12 +60,62 @@ TEST(LockTraits, SharedMutex) { ...@@ -56,12 +60,62 @@ TEST(LockTraits, SharedMutex) {
lock_shared_or_unique(mutex); lock_shared_or_unique(mutex);
unlock_shared_or_unique(mutex); unlock_shared_or_unique(mutex);
unlock_shared_or_unique(mutex); unlock_shared_or_unique(mutex);
traits::lock_upgrade(mutex);
traits::unlock_upgrade(mutex);
// test upgrade and downgrades
traits::lock_upgrade(mutex);
traits::unlock_upgrade_and_lock(mutex);
bool gotLock = traits::try_lock_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
"lock after upgrading to an exclusive lock";
gotLock = traits::try_lock_upgrade_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an upgrade "
"lock after upgrading to an exclusive lock";
gotLock = traits::try_lock_shared_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire a shared "
"lock after upgrading to an exclusive lock";
traits::unlock(mutex);
traits::lock_upgrade(mutex);
traits::unlock_upgrade_and_lock_shared(mutex);
gotLock = traits::try_lock_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
"mutex after downgrading from an upgrade to a "
"shared lock";
traits::unlock_shared(mutex);
traits::lock(mutex);
gotLock = traits::try_lock_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
"lock after acquiring an exclusive lock";
gotLock = traits::try_lock_upgrade_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an upgrade "
"lock after acquiring an exclusive lock";
gotLock = traits::try_lock_shared_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire a shared "
"lock after acquiring an exclusive lock";
traits::unlock_and_lock_upgrade(mutex);
gotLock = traits::try_lock_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
"lock after downgrading to an upgrade lock";
traits::unlock_upgrade(mutex);
traits::lock(mutex);
traits::unlock_and_lock_shared(mutex);
gotLock = traits::try_lock_for(mutex, one_ms);
EXPECT_FALSE(gotLock) << "Should not have been able to acquire an exclusive "
"lock after downgrading to a shared lock";
traits::unlock_shared(mutex);
} }
TEST(LockTraits, SpinLock) { TEST(LockTraits, SpinLock) {
using traits = LockTraits<SpinLock>; using traits = LockTraits<SpinLock>;
static_assert(!traits::is_timed, "folly::SpinLock is not a timed lock"); static_assert(!traits::is_timed, "folly::SpinLock is not a timed lock");
static_assert(!traits::is_shared, "folly::SpinLock is not a shared lock"); static_assert(!traits::is_shared, "folly::SpinLock is not a shared lock");
static_assert(
!traits::is_upgrade, "folly::SpinLock is not an upgradable lock");
SpinLock mutex; SpinLock mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -75,6 +129,7 @@ TEST(LockTraits, RWSpinLock) { ...@@ -75,6 +129,7 @@ TEST(LockTraits, RWSpinLock) {
using traits = LockTraits<RWSpinLock>; using traits = LockTraits<RWSpinLock>;
static_assert(!traits::is_timed, "folly::RWSpinLock is not a timed lock"); static_assert(!traits::is_timed, "folly::RWSpinLock is not a timed lock");
static_assert(traits::is_shared, "folly::RWSpinLock is a shared lock"); static_assert(traits::is_shared, "folly::RWSpinLock is a shared lock");
static_assert(traits::is_upgrade, "folly::RWSpinLock is an upgradable lock");
RWSpinLock mutex; RWSpinLock mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -95,6 +150,7 @@ TEST(LockTraits, boost_mutex) { ...@@ -95,6 +150,7 @@ TEST(LockTraits, boost_mutex) {
using traits = LockTraits<boost::mutex>; using traits = LockTraits<boost::mutex>;
static_assert(!traits::is_timed, "boost::mutex is not a timed lock"); static_assert(!traits::is_timed, "boost::mutex is not a timed lock");
static_assert(!traits::is_shared, "boost::mutex is not a shared lock"); static_assert(!traits::is_shared, "boost::mutex is not a shared lock");
static_assert(!traits::is_upgrade, "boost::mutex is not an upgradable lock");
boost::mutex mutex; boost::mutex mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -110,6 +166,8 @@ TEST(LockTraits, boost_recursive_mutex) { ...@@ -110,6 +166,8 @@ TEST(LockTraits, boost_recursive_mutex) {
!traits::is_timed, "boost::recursive_mutex is not a timed lock"); !traits::is_timed, "boost::recursive_mutex is not a timed lock");
static_assert( static_assert(
!traits::is_shared, "boost::recursive_mutex is not a shared lock"); !traits::is_shared, "boost::recursive_mutex is not a shared lock");
static_assert(
!traits::is_upgrade, "boost::recursive_mutex is not an upgradable lock");
boost::recursive_mutex mutex; boost::recursive_mutex mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -128,6 +186,8 @@ TEST(LockTraits, timed_mutex) { ...@@ -128,6 +186,8 @@ TEST(LockTraits, timed_mutex) {
using traits = LockTraits<std::timed_mutex>; using traits = LockTraits<std::timed_mutex>;
static_assert(traits::is_timed, "std::timed_mutex is a timed lock"); static_assert(traits::is_timed, "std::timed_mutex is a timed lock");
static_assert(!traits::is_shared, "std::timed_mutex is not a shared lock"); static_assert(!traits::is_shared, "std::timed_mutex is not a shared lock");
static_assert(
!traits::is_upgrade, "std::timed_mutex is not an upgradable lock");
std::timed_mutex mutex; std::timed_mutex mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -148,6 +208,9 @@ TEST(LockTraits, recursive_timed_mutex) { ...@@ -148,6 +208,9 @@ TEST(LockTraits, recursive_timed_mutex) {
static_assert(traits::is_timed, "std::recursive_timed_mutex is a timed lock"); static_assert(traits::is_timed, "std::recursive_timed_mutex is a timed lock");
static_assert( static_assert(
!traits::is_shared, "std::recursive_timed_mutex is not a shared lock"); !traits::is_shared, "std::recursive_timed_mutex is not a shared lock");
static_assert(
!traits::is_upgrade,
"std::recursive_timed_mutex is not an upgradable lock");
std::recursive_timed_mutex mutex; std::recursive_timed_mutex mutex;
traits::lock(mutex); traits::lock(mutex);
...@@ -169,6 +232,8 @@ TEST(LockTraits, boost_shared_mutex) { ...@@ -169,6 +232,8 @@ TEST(LockTraits, boost_shared_mutex) {
using traits = LockTraits<boost::shared_mutex>; using traits = LockTraits<boost::shared_mutex>;
static_assert(traits::is_timed, "boost::shared_mutex is a timed lock"); static_assert(traits::is_timed, "boost::shared_mutex is a timed lock");
static_assert(traits::is_shared, "boost::shared_mutex is a shared lock"); static_assert(traits::is_shared, "boost::shared_mutex is a shared lock");
static_assert(
traits::is_upgrade, "boost::shared_mutex is an upgradable lock");
boost::shared_mutex mutex; boost::shared_mutex mutex;
traits::lock(mutex); traits::lock(mutex);
......
...@@ -154,14 +154,12 @@ using CountPair = std::pair<int, int>; ...@@ -154,14 +154,12 @@ using CountPair = std::pair<int, int>;
// This class is specialized only to be uesed in SynchronizedLockTest // This class is specialized only to be uesed in SynchronizedLockTest
class FakeMutex { class FakeMutex {
public: public:
bool lock() { void lock() {
++lockCount_; ++lockCount_;
return true;
} }
bool unlock() { void unlock() {
++unlockCount_; ++unlockCount_;
return true;
} }
static CountPair getLockUnlockCount() { static CountPair getLockUnlockCount() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment