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/LockTraitsBoost.h>
22 #include <folly/Portability.h>
23 #include <folly/RWSpinLock.h>
24 #include <folly/SharedMutex.h>
25 #include <folly/SpinLock.h>
26 #include <folly/Synchronized.h>
27 #include <folly/test/SynchronizedTestLib.h>
28 #include <gtest/gtest.h>
30 using namespace folly::sync_tests;
32 template <class Mutex>
33 class SynchronizedTest : public testing::Test {};
35 using SynchronizedTestTypes = testing::Types<
36 folly::SharedMutexReadPriority,
37 folly::SharedMutexWritePriority,
40 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
42 std::recursive_timed_mutex,
45 boost::recursive_mutex,
46 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
48 boost::recursive_timed_mutex,
50 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
51 folly::RWTicketSpinLock32,
52 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 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
84 std::recursive_timed_mutex,
86 boost::recursive_timed_mutex,
89 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
90 folly::RWTicketSpinLock32,
91 folly::RWTicketSpinLock64,
93 folly::SharedMutexReadPriority,
94 folly::SharedMutexWritePriority>;
95 TYPED_TEST_CASE(SynchronizedTimedTest, SynchronizedTimedTestTypes);
97 TYPED_TEST(SynchronizedTimedTest, TimedSynchronized) {
98 testTimedSynchronized<TypeParam>();
101 template <class Mutex>
102 class SynchronizedTimedWithConstTest : public testing::Test {};
104 using SynchronizedTimedWithConstTestTypes = testing::Types<
105 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
108 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
109 folly::RWTicketSpinLock32,
110 folly::RWTicketSpinLock64,
112 folly::SharedMutexReadPriority,
113 folly::SharedMutexWritePriority>;
115 SynchronizedTimedWithConstTest, SynchronizedTimedWithConstTestTypes);
117 TYPED_TEST(SynchronizedTimedWithConstTest, TimedSynchronizeWithConst) {
118 testTimedSynchronizedWithConst<TypeParam>();
121 TYPED_TEST(SynchronizedTest, InPlaceConstruction) {
122 testInPlaceConstruction<TypeParam>();
125 using CountPair = std::pair<int, int>;
126 // This class is specialized only to be uesed in SynchronizedLockTest
139 static CountPair getLockUnlockCount() {
140 return CountPair{lockCount_, unlockCount_};
143 static void resetLockUnlockCount() {
148 // Keep these two static for test access
149 // Keep them thread_local in case of tests are run in parallel within one
151 static FOLLY_TLS int lockCount_;
152 static FOLLY_TLS int unlockCount_;
154 FOLLY_TLS int FakeMutex::lockCount_{0};
155 FOLLY_TLS int FakeMutex::unlockCount_{0};
157 // SynchronizedLockTest is used to verify the correct lock unlock behavior
158 // happens per design
159 class SynchronizedLockTest : public testing::Test {
161 void SetUp() override {
162 FakeMutex::resetLockUnlockCount();
166 // Single level of SYNCHRONIZED and UNSYNCHRONIZED, although nested test are
167 // super set of it, it is possible single level test passes while nested tests
169 TEST_F(SynchronizedLockTest, SyncUnSync) {
170 folly::Synchronized<std::vector<int>, FakeMutex> obj;
171 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
173 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
174 UNSYNCHRONIZED(obj) {
175 EXPECT_EQ((CountPair{1, 1}), FakeMutex::getLockUnlockCount());
177 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
179 EXPECT_EQ((CountPair{2, 2}), FakeMutex::getLockUnlockCount());
182 // Nested SYNCHRONIZED UNSYNCHRONIZED test, 2 levels for each are used here
183 TEST_F(SynchronizedLockTest, NestedSyncUnSync) {
184 folly::Synchronized<std::vector<int>, FakeMutex> obj;
185 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
186 SYNCHRONIZED(objCopy, obj) {
187 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
189 EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount());
190 UNSYNCHRONIZED(obj) {
191 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
192 UNSYNCHRONIZED(obj) {
193 EXPECT_EQ((CountPair{2, 2}),
194 FakeMutex::getLockUnlockCount());
196 EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount());
198 EXPECT_EQ((CountPair{4, 2}), FakeMutex::getLockUnlockCount());
200 EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount());
202 EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());
205 // Different nesting behavior, UNSYNCHRONIZED called on differen depth of
207 TEST_F(SynchronizedLockTest, NestedSyncUnSync2) {
208 folly::Synchronized<std::vector<int>, FakeMutex> obj;
209 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
210 SYNCHRONIZED(objCopy, obj) {
211 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
213 EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount());
214 UNSYNCHRONIZED(obj) {
215 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
217 EXPECT_EQ((CountPair{3, 1}), FakeMutex::getLockUnlockCount());
219 EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount());
220 UNSYNCHRONIZED(obj) {
221 EXPECT_EQ((CountPair{3, 3}), FakeMutex::getLockUnlockCount());
223 EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount());
225 EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());