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,
39 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
41 std::recursive_timed_mutex,
44 boost::recursive_mutex,
45 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
47 boost::recursive_timed_mutex,
49 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
50 folly::RWTicketSpinLock32,
51 folly::RWTicketSpinLock64,
55 TYPED_TEST_CASE(SynchronizedTest, SynchronizedTestTypes);
57 TYPED_TEST(SynchronizedTest, Basic) {
58 testBasic<TypeParam>();
61 TYPED_TEST(SynchronizedTest, Concurrency) {
62 testConcurrency<TypeParam>();
65 TYPED_TEST(SynchronizedTest, DualLocking) {
66 testDualLocking<TypeParam>();
69 TYPED_TEST(SynchronizedTest, DualLockingWithConst) {
70 testDualLockingWithConst<TypeParam>();
73 TYPED_TEST(SynchronizedTest, ConstCopy) {
74 testConstCopy<TypeParam>();
77 template <class Mutex>
78 class SynchronizedTimedTest : public testing::Test {};
80 using SynchronizedTimedTestTypes = testing::Types<
81 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
83 std::recursive_timed_mutex,
85 boost::recursive_timed_mutex,
88 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
89 folly::RWTicketSpinLock32,
90 folly::RWTicketSpinLock64,
92 folly::SharedMutexReadPriority,
93 folly::SharedMutexWritePriority>;
94 TYPED_TEST_CASE(SynchronizedTimedTest, SynchronizedTimedTestTypes);
96 TYPED_TEST(SynchronizedTimedTest, TimedSynchronized) {
97 testTimedSynchronized<TypeParam>();
100 template <class Mutex>
101 class SynchronizedTimedWithConstTest : public testing::Test {};
103 using SynchronizedTimedWithConstTestTypes = testing::Types<
104 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
107 #ifdef RW_SPINLOCK_USE_X86_INTRINSIC_
108 folly::RWTicketSpinLock32,
109 folly::RWTicketSpinLock64,
111 folly::SharedMutexReadPriority,
112 folly::SharedMutexWritePriority>;
114 SynchronizedTimedWithConstTest, SynchronizedTimedWithConstTestTypes);
116 TYPED_TEST(SynchronizedTimedWithConstTest, TimedSynchronizeWithConst) {
117 testTimedSynchronizedWithConst<TypeParam>();
120 TYPED_TEST(SynchronizedTest, InPlaceConstruction) {
121 testInPlaceConstruction<TypeParam>();
124 using CountPair = std::pair<int, int>;
125 // This class is specialized only to be uesed in SynchronizedLockTest
138 static CountPair getLockUnlockCount() {
139 return CountPair{lockCount_, unlockCount_};
142 static void resetLockUnlockCount() {
147 // Keep these two static for test access
148 // Keep them thread_local in case of tests are run in parallel within one
150 static FOLLY_TLS int lockCount_;
151 static FOLLY_TLS int unlockCount_;
153 FOLLY_TLS int FakeMutex::lockCount_{0};
154 FOLLY_TLS int FakeMutex::unlockCount_{0};
156 // SynchronizedLockTest is used to verify the correct lock unlock behavior
157 // happens per design
158 class SynchronizedLockTest : public testing::Test {
160 void SetUp() override {
161 FakeMutex::resetLockUnlockCount();
165 // Single level of SYNCHRONIZED and UNSYNCHRONIZED, although nested test are
166 // super set of it, it is possible single level test passes while nested tests
168 TEST_F(SynchronizedLockTest, SyncUnSync) {
169 folly::Synchronized<std::vector<int>, FakeMutex> obj;
170 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
172 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
173 UNSYNCHRONIZED(obj) {
174 EXPECT_EQ((CountPair{1, 1}), FakeMutex::getLockUnlockCount());
176 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
178 EXPECT_EQ((CountPair{2, 2}), FakeMutex::getLockUnlockCount());
181 // Nested SYNCHRONIZED UNSYNCHRONIZED test, 2 levels for each are used here
182 TEST_F(SynchronizedLockTest, NestedSyncUnSync) {
183 folly::Synchronized<std::vector<int>, FakeMutex> obj;
184 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
185 SYNCHRONIZED(objCopy, obj) {
186 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
188 EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount());
189 UNSYNCHRONIZED(obj) {
190 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
191 UNSYNCHRONIZED(obj) {
192 EXPECT_EQ((CountPair{2, 2}),
193 FakeMutex::getLockUnlockCount());
195 EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount());
197 EXPECT_EQ((CountPair{4, 2}), FakeMutex::getLockUnlockCount());
199 EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount());
201 EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());
204 // Different nesting behavior, UNSYNCHRONIZED called on differen depth of
206 TEST_F(SynchronizedLockTest, NestedSyncUnSync2) {
207 folly::Synchronized<std::vector<int>, FakeMutex> obj;
208 EXPECT_EQ((CountPair{0, 0}), FakeMutex::getLockUnlockCount());
209 SYNCHRONIZED(objCopy, obj) {
210 EXPECT_EQ((CountPair{1, 0}), FakeMutex::getLockUnlockCount());
212 EXPECT_EQ((CountPair{2, 0}), FakeMutex::getLockUnlockCount());
213 UNSYNCHRONIZED(obj) {
214 EXPECT_EQ((CountPair{2, 1}), FakeMutex::getLockUnlockCount());
216 EXPECT_EQ((CountPair{3, 1}), FakeMutex::getLockUnlockCount());
218 EXPECT_EQ((CountPair{3, 2}), FakeMutex::getLockUnlockCount());
219 UNSYNCHRONIZED(obj) {
220 EXPECT_EQ((CountPair{3, 3}), FakeMutex::getLockUnlockCount());
222 EXPECT_EQ((CountPair{4, 3}), FakeMutex::getLockUnlockCount());
224 EXPECT_EQ((CountPair{4, 4}), FakeMutex::getLockUnlockCount());