2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 // @author: Andrei Alexandrescu (aalexandre)
19 // Test bed for folly/Synchronized.h
21 #include <folly/Portability.h>
22 #include <folly/RWSpinLock.h>
23 #include <folly/SharedMutex.h>
24 #include <folly/SpinLock.h>
25 #include <folly/Synchronized.h>
26 #include <folly/test/SynchronizedTestLib.h>
27 #include <gtest/gtest.h>
31 template <class Mutex>
32 class SynchronizedTest : public testing::Test {};
34 using SynchronizedTestTypes = testing::Types
35 < folly::SharedMutexReadPriority
36 , folly::SharedMutexWritePriority
38 , std::recursive_mutex
39 #if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
41 , std::recursive_timed_mutex
44 , boost::recursive_mutex
45 #if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
47 , boost::recursive_timed_mutex
51 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
52 , folly::RWTicketSpinLock32
53 , folly::RWTicketSpinLock64
56 TYPED_TEST_CASE(SynchronizedTest, SynchronizedTestTypes);
58 TYPED_TEST(SynchronizedTest, Basic) {
59 testBasic<TypeParam>();
62 TYPED_TEST(SynchronizedTest, Concurrency) {
63 testConcurrency<TypeParam>();
66 TYPED_TEST(SynchronizedTest, DualLocking) {
67 testDualLocking<TypeParam>();
70 TYPED_TEST(SynchronizedTest, DualLockingWithConst) {
71 testDualLockingWithConst<TypeParam>();
74 TYPED_TEST(SynchronizedTest, ConstCopy) {
75 testConstCopy<TypeParam>();
78 template <class Mutex>
79 class SynchronizedTimedTest : public testing::Test {};
81 using SynchronizedTimedTestTypes = testing::Types
82 < folly::SharedMutexReadPriority
83 , folly::SharedMutexWritePriority
84 #if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
86 , std::recursive_timed_mutex
88 , boost::recursive_timed_mutex
91 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
92 , folly::RWTicketSpinLock32
93 , folly::RWTicketSpinLock64
96 TYPED_TEST_CASE(SynchronizedTimedTest, SynchronizedTimedTestTypes);
98 TYPED_TEST(SynchronizedTimedTest, TimedSynchronized) {
99 testTimedSynchronized<TypeParam>();
102 template <class Mutex>
103 class SynchronizedTimedWithConstTest : public testing::Test {};
105 using SynchronizedTimedWithConstTestTypes = testing::Types
106 < folly::SharedMutexReadPriority
107 , folly::SharedMutexWritePriority
108 #if FOLLY_SYNCHRONIZED_HAVE_TIMED_MUTEXES
109 , boost::shared_mutex
111 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
112 , folly::RWTicketSpinLock32
113 , folly::RWTicketSpinLock64
117 SynchronizedTimedWithConstTest, SynchronizedTimedWithConstTestTypes);
119 TYPED_TEST(SynchronizedTimedWithConstTest, TimedSynchronizeWithConst) {
120 testTimedSynchronizedWithConst<TypeParam>();
123 TYPED_TEST(SynchronizedTest, InPlaceConstruction) {
124 testInPlaceConstruction<TypeParam>();
127 using CountPair = std::pair<int, int>;
128 // This class is specialized only to be uesed in SynchronizedLockTest
141 static CountPair getLockUnlockCount() {
142 return CountPair{lockCount_, unlockCount_};
145 static void resetLockUnlockCount() {
150 // Keep these two static for test access
151 // Keep them thread_local in case of tests are run in parallel within one
153 static FOLLY_TLS int lockCount_;
154 static FOLLY_TLS int unlockCount_;
156 // Adapters for Synchronized<>
157 friend void acquireReadWrite(FakeMutex& lock) { lock.lock(); }
158 friend void releaseReadWrite(FakeMutex& lock) { lock.unlock(); }
160 FOLLY_TLS int FakeMutex::lockCount_{0};
161 FOLLY_TLS int FakeMutex::unlockCount_{0};
163 // SynchronizedLockTest is used to verify the correct lock unlock behavior
164 // happens per design
165 class SynchronizedLockTest : public testing::Test {
167 void SetUp() override {
168 FakeMutex::resetLockUnlockCount();
172 // Single level of SYNCHRONIZED and UNSYNCHRONIZED, although nested test are
173 // super set of it, it is possible single level test passes while nested tests
175 TEST_F(SynchronizedLockTest, SyncUnSync) {
176 folly::Synchronized<std::vector<int>, FakeMutex> obj;
177 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
179 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
180 UNSYNCHRONIZED(obj) {
181 EXPECT_EQ((CountPair{1, 1}), FakeMutex::getLockUnlockCount());
183 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
185 EXPECT_EQ((CountPair{2, 2}), FakeMutex::getLockUnlockCount());
188 // Nested SYNCHRONIZED UNSYNCHRONIZED test, 2 levels for each are used here
189 TEST_F(SynchronizedLockTest, NestedSyncUnSync) {
190 folly::Synchronized<std::vector<int>, FakeMutex> obj;
191 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
192 SYNCHRONIZED(objCopy, obj) {
193 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
195 EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount());
196 UNSYNCHRONIZED(obj) {
197 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
198 UNSYNCHRONIZED(obj) {
199 EXPECT_EQ((CountPair{2, 2}),
200 FakeMutex::getLockUnlockCount());
202 EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount());
204 EXPECT_EQ((CountPair{4, 2}), FakeMutex::getLockUnlockCount());
206 EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount());
208 EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());
211 // Different nesting behavior, UNSYNCHRONIZED called on differen depth of
213 TEST_F(SynchronizedLockTest, NestedSyncUnSync2) {
214 folly::Synchronized<std::vector<int>, FakeMutex> obj;
215 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
216 SYNCHRONIZED(objCopy, obj) {
217 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
219 EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount());
220 UNSYNCHRONIZED(obj) {
221 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
223 EXPECT_EQ((CountPair{3, 1}), FakeMutex::getLockUnlockCount());
225 EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount());
226 UNSYNCHRONIZED(obj) {
227 EXPECT_EQ((CountPair{3, 3}), FakeMutex::getLockUnlockCount());
229 EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount());
231 EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());