Commit 35ab212c authored by Aaryaman Sagar's avatar Aaryaman Sagar Committed by Facebook Github Bot

Add tryWLock, tryRLock, tryULock, tryWLock to folly::Synchronized

Summary:
Add `try_lock` methods to `folly::Synchronized` and add the corresponding
extensions to `LockTraits`.  These return `LockedPtr`s that are valid and
convert to true when the lock operation was successful, null otherwise

override-unit-failure

Reviewed By: yfeldblum, ot

Differential Revision: D7651765

fbshipit-source-id: eb85987a2e4476cd916747dfc2ae69d124690ee6
parent 9e63a755
...@@ -130,6 +130,13 @@ struct LockTraitsImpl<Mutex, MutexLevel::UNIQUE, false> { ...@@ -130,6 +130,13 @@ struct LockTraitsImpl<Mutex, MutexLevel::UNIQUE, false> {
static void unlock(Mutex& mutex) { static void unlock(Mutex& mutex) {
mutex.unlock(); mutex.unlock();
} }
/**
* Try to acquire the mutex
*/
static bool try_lock(Mutex& mutex) {
return mutex.try_lock();
}
}; };
/** /**
...@@ -156,6 +163,13 @@ struct LockTraitsImpl<Mutex, MutexLevel::SHARED, false> ...@@ -156,6 +163,13 @@ struct LockTraitsImpl<Mutex, MutexLevel::SHARED, false>
static void unlock_shared(Mutex& mutex) { static void unlock_shared(Mutex& mutex) {
mutex.unlock_shared(); mutex.unlock_shared();
} }
/**
* Try to acquire the mutex in shared mode
*/
static bool try_lock_shared(Mutex& mutex) {
return mutex.try_lock_shared();
}
}; };
/** /**
...@@ -163,6 +177,7 @@ struct LockTraitsImpl<Mutex, MutexLevel::SHARED, false> ...@@ -163,6 +177,7 @@ struct LockTraitsImpl<Mutex, MutexLevel::SHARED, false>
* *
* m.lock_upgrade() * m.lock_upgrade()
* m.unlock_upgrade() * m.unlock_upgrade()
* m.try_lock_upgrade()
* *
* m.unlock_upgrade_and_lock() * m.unlock_upgrade_and_lock()
* *
...@@ -206,6 +221,13 @@ struct LockTraitsImpl<Mutex, MutexLevel::UPGRADE, false> ...@@ -206,6 +221,13 @@ struct LockTraitsImpl<Mutex, MutexLevel::UPGRADE, false>
mutex.unlock_upgrade(); mutex.unlock_upgrade();
} }
/**
* Try and acquire the lock in upgrade mode
*/
static bool try_lock_upgrade(Mutex& mutex) {
return mutex.try_lock_upgrade();
}
/** /**
* Upgrade from an upgradable state to an exclusive state * Upgrade from an upgradable state to an exclusive state
*/ */
...@@ -350,15 +372,18 @@ struct LockTraitsImpl<Mutex, MutexLevel::UPGRADE, true> ...@@ -350,15 +372,18 @@ struct LockTraitsImpl<Mutex, MutexLevel::UPGRADE, true>
* The following static methods always exist: * The following static methods always exist:
* - lock(Mutex& mutex) * - lock(Mutex& mutex)
* - unlock(Mutex& mutex) * - unlock(Mutex& mutex)
* - try_lock(Mutex& mutex)
* *
* The following static methods may exist, depending on is_shared, is_timed * The following static methods may exist, depending on is_shared, is_timed
* and is_upgrade: * and is_upgrade:
* - lock_shared() * - lock_shared()
* - try_lock_shared()
* *
* - try_lock_for() * - try_lock_for()
* - try_lock_shared_for() * - try_lock_shared_for()
* *
* - lock_upgrade() * - lock_upgrade()
* - try_lock_upgrade()
* - unlock_upgrade_and_lock() * - unlock_upgrade_and_lock()
* - unlock_and_lock_upgrade() * - unlock_and_lock_upgrade()
* - unlock_and_lock_shared() * - unlock_and_lock_shared()
...@@ -452,8 +477,9 @@ unlock_shared_or_unique(Mutex& mutex) { ...@@ -452,8 +477,9 @@ unlock_shared_or_unique(Mutex& mutex) {
*/ */
struct LockPolicyExclusive { struct LockPolicyExclusive {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::lock(mutex); LockTraits<Mutex>::lock(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -473,8 +499,9 @@ struct LockPolicyExclusive { ...@@ -473,8 +499,9 @@ struct LockPolicyExclusive {
*/ */
struct LockPolicyShared { struct LockPolicyShared {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::lock_shared(mutex); LockTraits<Mutex>::lock_shared(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -494,8 +521,9 @@ struct LockPolicyShared { ...@@ -494,8 +521,9 @@ struct LockPolicyShared {
*/ */
struct LockPolicyShareable { struct LockPolicyShareable {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
lock_shared_or_unique(mutex); lock_shared_or_unique(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -518,8 +546,9 @@ struct LockPolicyShareable { ...@@ -518,8 +546,9 @@ struct LockPolicyShareable {
*/ */
struct LockPolicyUpgrade { struct LockPolicyUpgrade {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::lock_upgrade(mutex); LockTraits<Mutex>::lock_upgrade(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -533,6 +562,54 @@ struct LockPolicyUpgrade { ...@@ -533,6 +562,54 @@ struct LockPolicyUpgrade {
} }
}; };
/*****************************************************************************
* Policies for optional mutex locking
****************************************************************************/
/**
* A lock policy that tries to acquire write locks and returns true or false
* based on whether the lock operation succeeds
*/
struct LockPolicyTryExclusive {
template <class Mutex>
static bool lock(Mutex& mutex) {
return LockTraits<Mutex>::try_lock(mutex);
}
template <class Mutex>
static void unlock(Mutex& mutex) {
LockTraits<Mutex>::unlock(mutex);
}
};
/**
* A lock policy that tries to acquire a read lock and returns true or false
* based on whether the lock operation succeeds
*/
struct LockPolicyTryShared {
template <class Mutex>
static bool lock(Mutex& mutex) {
return LockTraits<Mutex>::try_lock_shared(mutex);
}
template <class Mutex>
static void unlock(Mutex& mutex) {
LockTraits<Mutex>::unlock_shared(mutex);
}
};
/**
* A lock policy that tries to acquire an upgrade lock and returns true or
* false based on whether the lock operation succeeds
*/
struct LockPolicyTryUpgrade {
template <class Mutex>
static bool lock(Mutex& mutex) {
return LockTraits<Mutex>::try_lock_upgrade(mutex);
}
template <class Mutex>
static void unlock(Mutex& mutex) {
LockTraits<Mutex>::unlock_upgrade(mutex);
}
};
/***************************************************************************** /*****************************************************************************
* Policies for all the transitions from possible mutex levels * Policies for all the transitions from possible mutex levels
****************************************************************************/ ****************************************************************************/
...@@ -545,8 +622,9 @@ struct LockPolicyUpgrade { ...@@ -545,8 +622,9 @@ struct LockPolicyUpgrade {
*/ */
struct LockPolicyFromUpgradeToExclusive : public LockPolicyExclusive { struct LockPolicyFromUpgradeToExclusive : public LockPolicyExclusive {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::unlock_upgrade_and_lock(mutex); LockTraits<Mutex>::unlock_upgrade_and_lock(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -565,8 +643,9 @@ struct LockPolicyFromUpgradeToExclusive : public LockPolicyExclusive { ...@@ -565,8 +643,9 @@ struct LockPolicyFromUpgradeToExclusive : public LockPolicyExclusive {
*/ */
struct LockPolicyFromExclusiveToUpgrade : public LockPolicyUpgrade { struct LockPolicyFromExclusiveToUpgrade : public LockPolicyUpgrade {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::unlock_and_lock_upgrade(mutex); LockTraits<Mutex>::unlock_and_lock_upgrade(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -588,8 +667,9 @@ struct LockPolicyFromExclusiveToUpgrade : public LockPolicyUpgrade { ...@@ -588,8 +667,9 @@ struct LockPolicyFromExclusiveToUpgrade : public LockPolicyUpgrade {
*/ */
struct LockPolicyFromUpgradeToShared : public LockPolicyShared { struct LockPolicyFromUpgradeToShared : public LockPolicyShared {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::unlock_upgrade_and_lock_shared(mutex); LockTraits<Mutex>::unlock_upgrade_and_lock_shared(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
...@@ -611,8 +691,9 @@ struct LockPolicyFromUpgradeToShared : public LockPolicyShared { ...@@ -611,8 +691,9 @@ struct LockPolicyFromUpgradeToShared : public LockPolicyShared {
*/ */
struct LockPolicyFromExclusiveToShared : public LockPolicyShared { struct LockPolicyFromExclusiveToShared : public LockPolicyShared {
template <class Mutex> template <class Mutex>
static void lock(Mutex& mutex) { static std::true_type lock(Mutex& mutex) {
LockTraits<Mutex>::unlock_and_lock_shared(mutex); LockTraits<Mutex>::unlock_and_lock_shared(mutex);
return std::true_type{};
} }
template <class Mutex, class Rep, class Period> template <class Mutex, class Rep, class Period>
static bool try_lock_for( static bool try_lock_for(
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#include <folly/SharedMutex.h> #include <folly/SharedMutex.h>
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/Utility.h> #include <folly/Utility.h>
#include <folly/container/Foreach.h>
#include <folly/functional/Invoke.h>
#include <folly/portability/GTest.h>
#include <glog/logging.h> #include <glog/logging.h>
#include <mutex> #include <mutex>
#include <type_traits> #include <type_traits>
...@@ -85,6 +88,11 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> { ...@@ -85,6 +88,11 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
::folly::LockedPtr<const Subclass, LockPolicyExclusive>; ::folly::LockedPtr<const Subclass, LockPolicyExclusive>;
using ConstLockedPtr = ::folly::LockedPtr<const Subclass, LockPolicyShared>; using ConstLockedPtr = ::folly::LockedPtr<const Subclass, LockPolicyShared>;
using TryWLockedPtr = ::folly::LockedPtr<Subclass, LockPolicyTryExclusive>;
using ConstTryWLockedPtr =
::folly::LockedPtr<const Subclass, LockPolicyTryExclusive>;
using TryRLockedPtr = ::folly::LockedPtr<const Subclass, LockPolicyTryShared>;
/** /**
* Acquire an exclusive lock, and return a LockedPtr that can be used to * Acquire an exclusive lock, and return a LockedPtr that can be used to
* safely access the datum. * safely access the datum.
...@@ -99,6 +107,20 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> { ...@@ -99,6 +107,20 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
return ConstWLockedPtr(static_cast<const Subclass*>(this)); return ConstWLockedPtr(static_cast<const Subclass*>(this));
} }
/**
* Attempts to acquire the lock in exclusive mode. If acquisition is
* unsuccessful, the returned LockedPtr will be null.
*
* (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
* validity.)
*/
TryWLockedPtr tryWLock() {
return TryWLockedPtr{static_cast<Subclass*>(this)};
}
ConstTryWLockedPtr tryWLock() const {
return ConstTryWLockedPtr{static_cast<const Subclass*>(this)};
}
/** /**
* Acquire a read lock, and return a ConstLockedPtr that can be used to * Acquire a read lock, and return a ConstLockedPtr that can be used to
* safely access the datum. * safely access the datum.
...@@ -107,11 +129,23 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> { ...@@ -107,11 +129,23 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
return ConstLockedPtr(static_cast<const Subclass*>(this)); return ConstLockedPtr(static_cast<const Subclass*>(this));
} }
/**
* Attempts to acquire the lock in shared mode. If acquisition is
* unsuccessful, the returned LockedPtr will be null.
*
* (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
* validity.)
*/
TryRLockedPtr tryRLock() const {
return TryRLockedPtr{static_cast<const Subclass*>(this)};
}
/** /**
* Attempts to acquire the lock, or fails if the timeout elapses first. * Attempts to acquire the lock, or fails if the timeout elapses first.
* If acquisition is unsuccessful, the returned LockedPtr will be null. * If acquisition is unsuccessful, the returned LockedPtr will be null.
* *
* (Use LockedPtr::isNull() to check for validity.) * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
* validity.)
*/ */
template <class Rep, class Period> template <class Rep, class Period>
LockedPtr wlock(const std::chrono::duration<Rep, Period>& timeout) { LockedPtr wlock(const std::chrono::duration<Rep, Period>& timeout) {
...@@ -127,7 +161,8 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> { ...@@ -127,7 +161,8 @@ class SynchronizedBase<Subclass, detail::MutexLevel::SHARED> {
* Attempts to acquire the lock, or fails if the timeout elapses first. * Attempts to acquire the lock, or fails if the timeout elapses first.
* If acquisition is unsuccessful, the returned LockedPtr will be null. * If acquisition is unsuccessful, the returned LockedPtr will be null.
* *
* (Use LockedPtr::isNull() to check for validity.) * (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
* validity.)
*/ */
template <class Rep, class Period> template <class Rep, class Period>
ConstLockedPtr rlock( ConstLockedPtr rlock(
...@@ -224,6 +259,11 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UPGRADE> ...@@ -224,6 +259,11 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UPGRADE>
using ConstUpgradeLockedGuardPtr = using ConstUpgradeLockedGuardPtr =
::folly::LockedGuardPtr<const Subclass, LockPolicyUpgrade>; ::folly::LockedGuardPtr<const Subclass, LockPolicyUpgrade>;
using TryUpgradeLockedPtr =
::folly::LockedPtr<Subclass, LockPolicyTryUpgrade>;
using ConstTryUpgradeLockedPtr =
::folly::LockedPtr<const Subclass, LockPolicyTryUpgrade>;
/** /**
* Acquire an upgrade lock and return a LockedPtr that can be used to safely * Acquire an upgrade lock and return a LockedPtr that can be used to safely
* access the datum * access the datum
...@@ -237,6 +277,20 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UPGRADE> ...@@ -237,6 +277,20 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UPGRADE>
return ConstUpgradeLockedPtr(static_cast<const Subclass*>(this)); return ConstUpgradeLockedPtr(static_cast<const Subclass*>(this));
} }
/**
* Attempts to acquire the lock in upgrade mode. If acquisition is
* unsuccessful, the returned LockedPtr will be null.
*
* (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
* validity.)
*/
TryUpgradeLockedPtr tryULock() {
return TryUpgradeLockedPtr{static_cast<Subclass*>(this)};
}
ConstTryUpgradeLockedPtr tryULock() const {
return ConstTryUpgradeLockedPtr{static_cast<const Subclass*>(this)};
}
/** /**
* Acquire an upgrade lock and return a LockedPtr that can be used to safely * Acquire an upgrade lock and return a LockedPtr that can be used to safely
* access the datum * access the datum
...@@ -314,6 +368,10 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UNIQUE> { ...@@ -314,6 +368,10 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UNIQUE> {
using ConstLockedPtr = using ConstLockedPtr =
::folly::LockedPtr<const Subclass, LockPolicyExclusive>; ::folly::LockedPtr<const Subclass, LockPolicyExclusive>;
using TryLockedPtr = ::folly::LockedPtr<Subclass, LockPolicyTryExclusive>;
using ConstTryLockedPtr =
::folly::LockedPtr<const Subclass, LockPolicyTryExclusive>;
/** /**
* Acquire a lock, and return a LockedPtr that can be used to safely access * Acquire a lock, and return a LockedPtr that can be used to safely access
* the datum. * the datum.
...@@ -330,6 +388,20 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UNIQUE> { ...@@ -330,6 +388,20 @@ class SynchronizedBase<Subclass, detail::MutexLevel::UNIQUE> {
return ConstLockedPtr(static_cast<const Subclass*>(this)); return ConstLockedPtr(static_cast<const Subclass*>(this));
} }
/**
* Attempts to acquire the lock in exclusive mode. If acquisition is
* unsuccessful, the returned LockedPtr will be null.
*
* (Use LockedPtr::operator bool() or LockedPtr::isNull() to check for
* validity.)
*/
TryLockedPtr tryLock() {
return TryLockedPtr{static_cast<Subclass*>(this)};
}
ConstTryLockedPtr tryLock() const {
return ConstTryLockedPtr{static_cast<const Subclass*>(this)};
}
/** /**
* Attempts to acquire the lock, or fails if the timeout elapses first. * Attempts to acquire the lock, or fails if the timeout elapses first.
* If acquisition is unsuccessful, the returned LockedPtr will be null. * If acquisition is unsuccessful, the returned LockedPtr will be null.
...@@ -849,7 +921,10 @@ class LockedPtrBase { ...@@ -849,7 +921,10 @@ class LockedPtrBase {
protected: protected:
LockedPtrBase() {} LockedPtrBase() {}
explicit LockedPtrBase(SynchronizedType* parent) : parent_(parent) { explicit LockedPtrBase(SynchronizedType* parent) : parent_(parent) {
LockPolicy::lock(parent_->mutex_); DCHECK(parent);
if (!LockPolicy::lock(parent_->mutex_)) {
parent_ = nullptr;
}
} }
template <class Rep, class Period> template <class Rep, class Period>
LockedPtrBase( LockedPtrBase(
...@@ -964,7 +1039,13 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> { ...@@ -964,7 +1039,13 @@ class LockedPtrBase<SynchronizedType, std::mutex, LockPolicy> {
protected: protected:
LockedPtrBase() {} LockedPtrBase() {}
explicit LockedPtrBase(SynchronizedType* parent) explicit LockedPtrBase(SynchronizedType* parent)
: lock_(parent->mutex_), parent_(parent) {} : lock_{parent->mutex_, std::adopt_lock}, parent_{parent} {
DCHECK(parent);
if (!LockPolicy::lock(parent_->mutex_)) {
parent_ = nullptr;
lock_.release();
}
}
using UnlockerData = using UnlockerData =
std::pair<std::unique_lock<std::mutex>, SynchronizedType*>; std::pair<std::unique_lock<std::mutex>, SynchronizedType*>;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
// Test bed for folly/Synchronized.h // Test bed for folly/Synchronized.h
#include <folly/Synchronized.h> #include <folly/Synchronized.h>
#include <folly/Function.h>
#include <folly/LockTraitsBoost.h> #include <folly/LockTraitsBoost.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/SharedMutex.h> #include <folly/SharedMutex.h>
...@@ -28,6 +29,8 @@ ...@@ -28,6 +29,8 @@
using namespace folly::sync_tests; using namespace folly::sync_tests;
namespace folly {
template <class Mutex> template <class Mutex>
class SynchronizedTest : public testing::Test {}; class SynchronizedTest : public testing::Test {};
...@@ -544,3 +547,145 @@ TEST_F(SynchronizedLockTest, TestPieceWiseConstruct) { ...@@ -544,3 +547,145 @@ TEST_F(SynchronizedLockTest, TestPieceWiseConstruct) {
EXPECT_EQ(*synchronized.lock(), 3); EXPECT_EQ(*synchronized.lock(), 3);
EXPECT_EQ(NonDefaultConstructibleMutex::value, 1); EXPECT_EQ(NonDefaultConstructibleMutex::value, 1);
} }
namespace {
constexpr auto kLockable = 1;
constexpr auto kWLockable = 2;
constexpr auto kRLockable = 4;
constexpr auto kULockable = 8;
template <int kLockableType>
class TryLockable {
public:
explicit TryLockable(
bool shouldSucceed,
folly::Function<void()> onLockIn,
folly::Function<void()> onUnlockIn)
: kShouldSucceed{shouldSucceed},
onLock{std::move(onLockIn)},
onUnlock{std::move(onUnlockIn)} {}
void lock() {
EXPECT_TRUE(false);
}
template <
int LockableType = kLockableType,
std::enable_if_t<LockableType != kLockable>* = nullptr>
void lock_shared() {
EXPECT_TRUE(false);
}
template <
int LockableType = kLockableType,
std::enable_if_t<LockableType == kULockable>* = nullptr>
void lock_upgrade() {
EXPECT_TRUE(false);
}
bool tryLockImpl(int lockableMask) {
// if the lockable type of this instance is one of the possible options as
// expressed in the mask go through the usual test code
if (kLockableType | lockableMask) {
if (kShouldSucceed) {
onLock();
return true;
} else {
return false;
}
}
// else fail the test
EXPECT_TRUE(false);
return false;
}
void unlockImpl(int lockableMask) {
if (kLockableType | lockableMask) {
onUnlock();
return;
}
EXPECT_TRUE(false);
}
bool try_lock() {
return tryLockImpl(kLockable | kWLockable);
}
bool try_lock_shared() {
return tryLockImpl(kRLockable);
}
bool try_lock_upgrade() {
return tryLockImpl(kULockable);
}
void unlock() {
unlockImpl(kLockable | kWLockable);
}
void unlock_shared() {
unlockImpl(kLockable | kRLockable);
}
void unlock_upgrade() {
unlockImpl(kLockable | kULockable);
}
const bool kShouldSucceed;
folly::Function<void()> onLock;
folly::Function<void()> onUnlock;
};
template <int kLockable, typename Func>
void testTryLock(Func func) {
{
auto locked = 0;
auto unlocked = 0;
folly::Synchronized<int, TryLockable<kLockable>> synchronized{
std::piecewise_construct,
std::make_tuple(),
std::make_tuple(true, [&] { ++locked; }, [&] { ++unlocked; })};
{
auto lock = func(synchronized);
EXPECT_TRUE(lock);
EXPECT_EQ(locked, 1);
}
EXPECT_EQ(locked, 1);
EXPECT_EQ(unlocked, 1);
}
{
auto locked = 0;
auto unlocked = 0;
folly::Synchronized<int, TryLockable<kLockable>> synchronized{
std::piecewise_construct,
std::make_tuple(),
std::make_tuple(false, [&] { ++locked; }, [&] { ++unlocked; })};
{
auto lock = func(synchronized);
EXPECT_FALSE(lock);
EXPECT_EQ(locked, 0);
}
EXPECT_EQ(locked, 0);
EXPECT_EQ(unlocked, 0);
}
}
} // namespace
TEST_F(SynchronizedLockTest, TestTryLock) {
testTryLock<kLockable>(
[](auto& synchronized) { return synchronized.tryLock(); });
}
TEST_F(SynchronizedLockTest, TestTryWLock) {
testTryLock<kWLockable>(
[](auto& synchronized) { return synchronized.tryWLock(); });
}
TEST_F(SynchronizedLockTest, TestTryRLock) {
testTryLock<kRLockable>(
[](auto& synchronized) { return synchronized.tryRLock(); });
}
TEST_F(SynchronizedLockTest, TestTryULock) {
testTryLock<kULockable>(
[](auto& synchronized) { return synchronized.tryULock(); });
}
} // namespace folly
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