*/
template <class T>
struct HasLockUnlock {
- enum { value = IsOneOf<T,
- std::mutex, std::recursive_mutex,
- boost::mutex, boost::recursive_mutex, boost::shared_mutex
+ enum { value = IsOneOf<T
+ , std::mutex
+ , std::recursive_mutex
+ , boost::mutex
+ , boost::recursive_mutex
+ , boost::shared_mutex
#if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
- ,std::timed_mutex, std::recursive_timed_mutex,
- boost::timed_mutex, boost::recursive_timed_mutex
+ , std::timed_mutex
+ , std::recursive_timed_mutex
+ , boost::timed_mutex
+ , boost::recursive_timed_mutex
#endif
- >::value };
+ >::value };
};
/**
- * Acquires a mutex for reading by calling .lock(). The exception is
- * boost::shared_mutex, which has a special read-lock primitive called
- * .lock_shared().
+ * Yields true iff T has .lock_shared() and .unlock_shared() member functions.
+ * This is done by simply enumerating the mutexes with this interface.
*/
template <class T>
-typename std::enable_if<
- HasLockUnlock<T>::value && !std::is_same<T, boost::shared_mutex>::value>::type
-acquireRead(T& mutex) {
- mutex.lock();
-}
+struct HasLockSharedUnlockShared {
+ enum { value = IsOneOf<T
+ , boost::shared_mutex
+ >::value };
+};
/**
- * Special case for boost::shared_mutex.
+ * Acquires a mutex for reading by calling .lock().
+ *
+ * This variant is not appropriate for shared mutexes.
*/
template <class T>
-typename std::enable_if<std::is_same<T, boost::shared_mutex>::value>::type
+typename std::enable_if<
+ HasLockUnlock<T>::value && !HasLockSharedUnlockShared<T>::value>::type
acquireRead(T& mutex) {
- mutex.lock_shared();
+ mutex.lock();
}
/**
- * Acquires a mutex for reading with timeout by calling .timed_lock(). This
- * applies to three of the boost mutex classes as enumerated below.
+ * Acquires a mutex for reading by calling .lock_shared().
+ *
+ * This variant is not appropriate for nonshared mutexes.
*/
template <class T>
-typename std::enable_if<std::is_same<T, boost::shared_mutex>::value, bool>::type
-acquireRead(T& mutex,
- unsigned int milliseconds) {
- return mutex.timed_lock_shared(boost::posix_time::milliseconds(milliseconds));
+typename std::enable_if<HasLockSharedUnlockShared<T>::value>::type
+acquireRead(T& mutex) {
+ mutex.lock_shared();
}
/**
}
#if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
+/**
+ * Acquires a mutex for reading by calling .try_lock_shared_for(). This applies
+ * to boost::shared_mutex.
+ */
+template <class T>
+typename std::enable_if<
+ IsOneOf<T
+ , boost::shared_mutex
+ >::value, bool>::type
+acquireRead(T& mutex,
+ unsigned int milliseconds) {
+ return mutex.try_lock_shared_for(boost::chrono::milliseconds(milliseconds));
+}
+
/**
* Acquires a mutex for reading and writing with timeout by calling
* .try_lock_for(). This applies to two of the std mutex classes as
*/
template <class T>
typename std::enable_if<
- IsOneOf<T, std::timed_mutex, std::recursive_timed_mutex>::value, bool>::type
+ IsOneOf<T
+ , std::timed_mutex
+ , std::recursive_timed_mutex
+ >::value, bool>::type
acquireReadWrite(T& mutex,
unsigned int milliseconds) {
// work around try_lock_for bug in some gcc versions, see
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54562
+ // TODO: Fixed in gcc-4.9.0.
return mutex.try_lock()
|| (milliseconds > 0 &&
mutex.try_lock_until(std::chrono::system_clock::now() +
/**
* Acquires a mutex for reading and writing with timeout by calling
- * .timed_lock(). This applies to three of the boost mutex classes as
+ * .try_lock_for(). This applies to three of the boost mutex classes as
* enumerated below.
*/
template <class T>
typename std::enable_if<
- IsOneOf<T, boost::shared_mutex, boost::timed_mutex,
- boost::recursive_timed_mutex>::value, bool>::type
+ IsOneOf<T
+ , boost::shared_mutex
+ , boost::timed_mutex
+ , boost::recursive_timed_mutex
+ >::value, bool>::type
acquireReadWrite(T& mutex,
unsigned int milliseconds) {
- return mutex.timed_lock(boost::posix_time::milliseconds(milliseconds));
+ return mutex.try_lock_for(boost::chrono::milliseconds(milliseconds));
}
#endif // FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
*/
template <class T>
typename std::enable_if<
- HasLockUnlock<T>::value && !std::is_same<T, boost::shared_mutex>::value>::type
+ HasLockUnlock<T>::value && !HasLockSharedUnlockShared<T>::value>::type
releaseRead(T& mutex) {
mutex.unlock();
}
* Special case for boost::shared_mutex.
*/
template <class T>
-typename std::enable_if<std::is_same<T, boost::shared_mutex>::value>::type
+typename std::enable_if<HasLockSharedUnlockShared<T>::value>::type
releaseRead(T& mutex) {
mutex.unlock_shared();
}
acquire();
}
ConstLockedPtr(const Synchronized* parent, unsigned int milliseconds) {
- if (parent->mutex_.timed_lock_shared(
- boost::posix_time::milliseconds(milliseconds))) {
+ using namespace detail;
+ if (acquireRead(
+ parent->mutex_,
+ milliseconds)) {
parent_ = parent;
return;
}
#include <folly/Synchronized.h>
#include <folly/RWSpinLock.h>
+#include <folly/SharedMutex.h>
#include <folly/test/SynchronizedTestLib.h>
#include <gtest/gtest.h>
+namespace {
-TEST(Synchronized, Basic) {
- testBasic<std::mutex>();
- testBasic<std::recursive_mutex>();
-#ifndef __APPLE__
- testBasic<std::timed_mutex>();
- testBasic<std::recursive_timed_mutex>();
-#endif
+template <class Mutex>
+class SynchronizedTest : public testing::Test {};
+using SynchronizedTestTypes = testing::Types
+ < folly::SharedMutexReadPriority
+ , folly::SharedMutexWritePriority
+ , std::mutex
+ , std::recursive_mutex
+#ifdef FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
+ , std::timed_mutex
+ , std::recursive_timed_mutex
+#endif
+ , boost::mutex
+ , boost::recursive_mutex
+#ifdef FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
+ , boost::timed_mutex
+ , boost::recursive_timed_mutex
+#endif
+ , boost::shared_mutex
#ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
- testBasic<folly::RWTicketSpinLock32>();
+ , folly::RWTicketSpinLock32
+ , folly::RWTicketSpinLock64
#endif
+ >;
+TYPED_TEST_CASE(SynchronizedTest, SynchronizedTestTypes);
- testBasic<boost::mutex>();
- testBasic<boost::recursive_mutex>();
- testBasic<boost::shared_mutex>();
-#ifndef __APPLE__
- testBasic<boost::timed_mutex>();
- testBasic<boost::recursive_timed_mutex>();
-#endif
+TYPED_TEST(SynchronizedTest, Basic) {
+ testBasic<TypeParam>();
}
-TEST(Synchronized, Concurrency) {
- testConcurrency<std::mutex>();
- testConcurrency<std::recursive_mutex>();
-#ifndef __APPLE__
- testConcurrency<std::timed_mutex>();
- testConcurrency<std::recursive_timed_mutex>();
-#endif
+TYPED_TEST(SynchronizedTest, Concurrency) {
+ testConcurrency<TypeParam>();
+}
-#ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
- testConcurrency<folly::RWTicketSpinLock32>();
-#endif
+TYPED_TEST(SynchronizedTest, DualLocking) {
+ testDualLocking<TypeParam>();
+}
- testConcurrency<boost::mutex>();
- testConcurrency<boost::recursive_mutex>();
- testConcurrency<boost::shared_mutex>();
-#ifndef __APPLE__
- testConcurrency<boost::timed_mutex>();
- testConcurrency<boost::recursive_timed_mutex>();
-#endif
+TYPED_TEST(SynchronizedTest, DualLockingWithConst) {
+ testDualLockingWithConst<TypeParam>();
}
+TYPED_TEST(SynchronizedTest, ConstCopy) {
+ testConstCopy<TypeParam>();
+}
-TEST(Synchronized, DualLocking) {
- testDualLocking<std::mutex>();
- testDualLocking<std::recursive_mutex>();
-#ifndef __APPLE__
- testDualLocking<std::timed_mutex>();
- testDualLocking<std::recursive_timed_mutex>();
+template <class Mutex>
+class SynchronizedTimedTest : public testing::Test {};
+
+using SynchronizedTimedTestTypes = testing::Types
+ < folly::SharedMutexReadPriority
+ , folly::SharedMutexWritePriority
+#ifdef FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
+ , std::timed_mutex
+ , std::recursive_timed_mutex
+ , boost::timed_mutex
+ , boost::recursive_timed_mutex
+ , boost::shared_mutex
#endif
-
#ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
- testDualLocking<folly::RWTicketSpinLock32>();
+ , folly::RWTicketSpinLock32
+ , folly::RWTicketSpinLock64
#endif
+ >;
+TYPED_TEST_CASE(SynchronizedTimedTest, SynchronizedTimedTestTypes);
- testDualLocking<boost::mutex>();
- testDualLocking<boost::recursive_mutex>();
- testDualLocking<boost::shared_mutex>();
-#ifndef __APPLE__
- testDualLocking<boost::timed_mutex>();
- testDualLocking<boost::recursive_timed_mutex>();
-#endif
+TYPED_TEST(SynchronizedTimedTest, TimedSynchronized) {
+ testTimedSynchronized<TypeParam>();
}
+template <class Mutex>
+class SynchronizedTimedWithConstTest : public testing::Test {};
-TEST(Synchronized, DualLockingWithConst) {
- testDualLockingWithConst<std::mutex>();
- testDualLockingWithConst<std::recursive_mutex>();
-#ifndef __APPLE__
- testDualLockingWithConst<std::timed_mutex>();
- testDualLockingWithConst<std::recursive_timed_mutex>();
+using SynchronizedTimedWithConstTestTypes = testing::Types
+ < folly::SharedMutexReadPriority
+ , folly::SharedMutexWritePriority
+#ifdef FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
+ , boost::shared_mutex
#endif
-
#ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
- testDualLockingWithConst<folly::RWTicketSpinLock32>();
+ , folly::RWTicketSpinLock32
+ , folly::RWTicketSpinLock64
#endif
+ >;
+TYPED_TEST_CASE(
+ SynchronizedTimedWithConstTest, SynchronizedTimedWithConstTestTypes);
- testDualLockingWithConst<boost::mutex>();
- testDualLockingWithConst<boost::recursive_mutex>();
- testDualLockingWithConst<boost::shared_mutex>();
-#ifndef __APPLE__
- testDualLockingWithConst<boost::timed_mutex>();
- testDualLockingWithConst<boost::recursive_timed_mutex>();
-#endif
+TYPED_TEST(SynchronizedTimedWithConstTest, TimedSynchronizeWithConst) {
+ testTimedSynchronizedWithConst<TypeParam>();
}
-
-#ifndef __APPLE__
-TEST(Synchronized, TimedSynchronized) {
- testTimedSynchronized<std::timed_mutex>();
- testTimedSynchronized<std::recursive_timed_mutex>();
-
- testTimedSynchronized<boost::timed_mutex>();
- testTimedSynchronized<boost::recursive_timed_mutex>();
- testTimedSynchronized<boost::shared_mutex>();
-
- testTimedSynchronizedWithConst<boost::shared_mutex>();
-}
-#endif
-
-TEST(Synchronized, ConstCopy) {
-#ifndef __APPLE__
- testConstCopy<std::timed_mutex>();
- testConstCopy<std::recursive_timed_mutex>();
-
- testConstCopy<boost::timed_mutex>();
- testConstCopy<boost::recursive_timed_mutex>();
-#endif
- testConstCopy<boost::shared_mutex>();
}