X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Ftest%2FSynchronizedTest.cpp;h=de45a4045b97d237dec722a4654f146fb99c9262;hb=b179601dfc42d8e3230d6477d7db8f3d5a8f64dc;hp=17ede7404cbf56523f99f8319b02a5cb956dbe97;hpb=ce64f0f685111ac24c7a321ea56d0c3524621df1;p=folly.git diff --git a/folly/test/SynchronizedTest.cpp b/folly/test/SynchronizedTest.cpp index 17ede740..de45a404 100644 --- a/folly/test/SynchronizedTest.cpp +++ b/folly/test/SynchronizedTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2016 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,119 +18,236 @@ // Test bed for folly/Synchronized.h -#include +#include +#include #include +#include +#include +#include #include #include +using namespace folly::sync_tests; -TEST(Synchronized, Basic) { - testBasic(); - testBasic(); -#ifndef __APPLE__ - testBasic(); - testBasic(); -#endif +template +class SynchronizedTest : public testing::Test {}; +using SynchronizedTestTypes = testing::Types< + folly::SharedMutexReadPriority, + folly::SharedMutexWritePriority, + std::mutex, + std::recursive_mutex, +#if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES + std::timed_mutex, + std::recursive_timed_mutex, +#endif + boost::mutex, + boost::recursive_mutex, +#if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES + boost::timed_mutex, + boost::recursive_timed_mutex, +#endif #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_ - testBasic(); + folly::RWTicketSpinLock32, + folly::RWTicketSpinLock64, #endif + boost::shared_mutex, + folly::SpinLock>; +TYPED_TEST_CASE(SynchronizedTest, SynchronizedTestTypes); - testBasic(); - testBasic(); - testBasic(); -#ifndef __APPLE__ - testBasic(); - testBasic(); -#endif +TYPED_TEST(SynchronizedTest, Basic) { + testBasic(); } -TEST(Synchronized, Concurrency) { - testConcurrency(); - testConcurrency(); -#ifndef __APPLE__ - testConcurrency(); - testConcurrency(); -#endif +TYPED_TEST(SynchronizedTest, WithLock) { + testWithLock(); +} -#ifdef RW_SPINLOCK_USE_X86_INTRINSIC_ - testConcurrency(); -#endif +TYPED_TEST(SynchronizedTest, Deprecated) { + testDeprecated(); +} - testConcurrency(); - testConcurrency(); - testConcurrency(); -#ifndef __APPLE__ - testConcurrency(); - testConcurrency(); -#endif +TYPED_TEST(SynchronizedTest, Concurrency) { + testConcurrency(); +} + +TYPED_TEST(SynchronizedTest, AcquireLocked) { + testAcquireLocked(); } +TYPED_TEST(SynchronizedTest, AcquireLockedWithConst) { + testAcquireLockedWithConst(); +} -TEST(Synchronized, DualLocking) { - testDualLocking(); - testDualLocking(); -#ifndef __APPLE__ - testDualLocking(); - testDualLocking(); -#endif +TYPED_TEST(SynchronizedTest, DualLocking) { + testDualLocking(); +} +TYPED_TEST(SynchronizedTest, DualLockingWithConst) { + testDualLockingWithConst(); +} + +TYPED_TEST(SynchronizedTest, ConstCopy) { + testConstCopy(); +} + +template +class SynchronizedTimedTest : public testing::Test {}; + +using SynchronizedTimedTestTypes = testing::Types< +#if FOLLY_LOCK_TRAITS_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::RWTicketSpinLock64, #endif + folly::SharedMutexReadPriority, + folly::SharedMutexWritePriority>; +TYPED_TEST_CASE(SynchronizedTimedTest, SynchronizedTimedTestTypes); - testDualLocking(); - testDualLocking(); - testDualLocking(); -#ifndef __APPLE__ - testDualLocking(); - testDualLocking(); -#endif +TYPED_TEST(SynchronizedTimedTest, Timed) { + testTimed(); } +TYPED_TEST(SynchronizedTimedTest, TimedSynchronized) { + testTimedSynchronized(); +} -TEST(Synchronized, DualLockingWithConst) { - testDualLockingWithConst(); - testDualLockingWithConst(); -#ifndef __APPLE__ - testDualLockingWithConst(); - testDualLockingWithConst(); -#endif +template +class SynchronizedTimedWithConstTest : public testing::Test {}; +using SynchronizedTimedWithConstTestTypes = testing::Types< +#if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES + boost::shared_mutex, +#endif #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_ - testDualLockingWithConst(); + folly::RWTicketSpinLock32, + folly::RWTicketSpinLock64, #endif + folly::SharedMutexReadPriority, + folly::SharedMutexWritePriority>; +TYPED_TEST_CASE( + SynchronizedTimedWithConstTest, SynchronizedTimedWithConstTestTypes); - testDualLockingWithConst(); - testDualLockingWithConst(); - testDualLockingWithConst(); -#ifndef __APPLE__ - testDualLockingWithConst(); - testDualLockingWithConst(); -#endif +TYPED_TEST(SynchronizedTimedWithConstTest, TimedShared) { + testTimedShared(); } +TYPED_TEST(SynchronizedTimedWithConstTest, TimedSynchronizeWithConst) { + testTimedSynchronizedWithConst(); +} -#ifndef __APPLE__ -TEST(Synchronized, TimedSynchronized) { - testTimedSynchronized(); - testTimedSynchronized(); - - testTimedSynchronized(); - testTimedSynchronized(); - testTimedSynchronized(); +TYPED_TEST(SynchronizedTest, InPlaceConstruction) { + testInPlaceConstruction(); +} - testTimedSynchronizedWithConst(); +using CountPair = std::pair; +// This class is specialized only to be uesed in SynchronizedLockTest +class FakeMutex { + public: + bool lock() { + ++lockCount_; + return true; + } + + bool unlock() { + ++unlockCount_; + return true; + } + + static CountPair getLockUnlockCount() { + return CountPair{lockCount_, unlockCount_}; + } + + static void resetLockUnlockCount() { + lockCount_ = 0; + unlockCount_ = 0; + } + private: + // Keep these two static for test access + // Keep them thread_local in case of tests are run in parallel within one + // process + static FOLLY_TLS int lockCount_; + static FOLLY_TLS int unlockCount_; +}; +FOLLY_TLS int FakeMutex::lockCount_{0}; +FOLLY_TLS int FakeMutex::unlockCount_{0}; + +// SynchronizedLockTest is used to verify the correct lock unlock behavior +// happens per design +class SynchronizedLockTest : public testing::Test { + public: + void SetUp() override { + FakeMutex::resetLockUnlockCount(); + } +}; + +// Single level of SYNCHRONIZED and UNSYNCHRONIZED, although nested test are +// super set of it, it is possible single level test passes while nested tests +// fail +TEST_F(SynchronizedLockTest, SyncUnSync) { + folly::Synchronized, FakeMutex> obj; + EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount()); + SYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount()); + UNSYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{1, 1}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{2, 2}), FakeMutex::getLockUnlockCount()); } -#endif -TEST(Synchronized, ConstCopy) { -#ifndef __APPLE__ - testConstCopy(); - testConstCopy(); +// Nested SYNCHRONIZED UNSYNCHRONIZED test, 2 levels of synchronization +TEST_F(SynchronizedLockTest, NestedSyncUnSync) { + folly::Synchronized, FakeMutex> obj; + EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount()); + SYNCHRONIZED(objCopy, obj) { + EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount()); + SYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount()); + // Note: UNSYNCHRONIZED has always been kind of broken here. + // The input parameter is ignored (other than to overwrite what the input + // variable name refers to), and it unlocks the most object acquired in + // the most recent SYNCHRONIZED scope. + UNSYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{3, 1}), FakeMutex::getLockUnlockCount()); + UNSYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{4, 2}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount()); +} - testConstCopy(); - testConstCopy(); -#endif - testConstCopy(); +// Different nesting behavior, UNSYNCHRONIZED called on different depth of +// SYNCHRONIZED +TEST_F(SynchronizedLockTest, NestedSyncUnSync2) { + folly::Synchronized, FakeMutex> obj; + EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount()); + SYNCHRONIZED(objCopy, obj) { + EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount()); + SYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount()); + UNSYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{3, 1}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount()); + UNSYNCHRONIZED(obj) { + EXPECT_EQ((CountPair{3, 3}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount()); + } + EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount()); }