add LockTraits
[folly.git] / folly / test / LockTraitsTest.cpp
1 /*
2  * Copyright 2016 Facebook, Inc.
3  *
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
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 #include <folly/LockTraits.h>
17 #include <folly/LockTraitsBoost.h>
18
19 #include <gtest/gtest.h>
20 #include <mutex>
21
22 #include <folly/RWSpinLock.h>
23 #include <folly/SharedMutex.h>
24 #include <folly/SpinLock.h>
25
26 using namespace folly;
27
28 TEST(LockTraits, std_mutex) {
29   using traits = LockTraits<std::mutex>;
30   static_assert(!traits::is_timed, "std:mutex is not a timed lock");
31   static_assert(!traits::is_shared, "std:mutex is not a shared lock");
32
33   std::mutex mutex;
34   traits::lock(mutex);
35   traits::unlock(mutex);
36
37   lock_shared_or_unique(mutex);
38   unlock_shared_or_unique(mutex);
39 }
40
41 TEST(LockTraits, SharedMutex) {
42   using traits = LockTraits<SharedMutex>;
43   static_assert(traits::is_timed, "SharedMutex is a timed lock");
44   static_assert(traits::is_shared, "SharedMutex is a shared lock");
45
46   SharedMutex mutex;
47   traits::lock(mutex);
48   traits::unlock(mutex);
49
50   traits::lock_shared(mutex);
51   traits::lock_shared(mutex);
52   traits::unlock_shared(mutex);
53   traits::unlock_shared(mutex);
54
55   lock_shared_or_unique(mutex);
56   lock_shared_or_unique(mutex);
57   unlock_shared_or_unique(mutex);
58   unlock_shared_or_unique(mutex);
59 }
60
61 TEST(LockTraits, SpinLock) {
62   using traits = LockTraits<SpinLock>;
63   static_assert(!traits::is_timed, "folly::SpinLock is not a timed lock");
64   static_assert(!traits::is_shared, "folly::SpinLock is not a shared lock");
65
66   SpinLock mutex;
67   traits::lock(mutex);
68   traits::unlock(mutex);
69
70   lock_shared_or_unique(mutex);
71   unlock_shared_or_unique(mutex);
72 }
73
74 TEST(LockTraits, RWSpinLock) {
75   using traits = LockTraits<RWSpinLock>;
76   static_assert(!traits::is_timed, "folly::RWSpinLock is not a timed lock");
77   static_assert(traits::is_shared, "folly::RWSpinLock is a shared lock");
78
79   RWSpinLock mutex;
80   traits::lock(mutex);
81   traits::unlock(mutex);
82
83   traits::lock_shared(mutex);
84   traits::lock_shared(mutex);
85   traits::unlock_shared(mutex);
86   traits::unlock_shared(mutex);
87
88   lock_shared_or_unique(mutex);
89   lock_shared_or_unique(mutex);
90   unlock_shared_or_unique(mutex);
91   unlock_shared_or_unique(mutex);
92 }
93
94 TEST(LockTraits, boost_mutex) {
95   using traits = LockTraits<boost::mutex>;
96   static_assert(!traits::is_timed, "boost::mutex is not a timed lock");
97   static_assert(!traits::is_shared, "boost::mutex is not a shared lock");
98
99   boost::mutex mutex;
100   traits::lock(mutex);
101   traits::unlock(mutex);
102
103   lock_shared_or_unique(mutex);
104   unlock_shared_or_unique(mutex);
105 }
106
107 TEST(LockTraits, boost_recursive_mutex) {
108   using traits = LockTraits<boost::recursive_mutex>;
109   static_assert(
110       !traits::is_timed, "boost::recursive_mutex is not a timed lock");
111   static_assert(
112       !traits::is_shared, "boost::recursive_mutex is not a shared lock");
113
114   boost::recursive_mutex mutex;
115   traits::lock(mutex);
116   traits::lock(mutex);
117   traits::unlock(mutex);
118   traits::unlock(mutex);
119
120   lock_shared_or_unique(mutex);
121   lock_shared_or_unique(mutex);
122   unlock_shared_or_unique(mutex);
123   unlock_shared_or_unique(mutex);
124 }
125
126 #if FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES
127 TEST(LockTraits, timed_mutex) {
128   using traits = LockTraits<std::timed_mutex>;
129   static_assert(traits::is_timed, "std::timed_mutex is a timed lock");
130   static_assert(!traits::is_shared, "std::timed_mutex is not a shared lock");
131
132   std::timed_mutex mutex;
133   traits::lock(mutex);
134   bool gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
135   EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
136                         << "timed_mutex a second time";
137   traits::unlock(mutex);
138
139   lock_shared_or_unique(mutex);
140   gotLock = try_lock_shared_or_unique_for(mutex, std::chrono::milliseconds(1));
141   EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
142                         << "timed_mutex a second time";
143   unlock_shared_or_unique(mutex);
144 }
145
146 TEST(LockTraits, recursive_timed_mutex) {
147   using traits = LockTraits<std::recursive_timed_mutex>;
148   static_assert(traits::is_timed, "std::recursive_timed_mutex is a timed lock");
149   static_assert(
150       !traits::is_shared, "std::recursive_timed_mutex is not a shared lock");
151
152   std::recursive_timed_mutex mutex;
153   traits::lock(mutex);
154   auto gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(10));
155   EXPECT_TRUE(gotLock) << "should have been able to acquire the "
156                        << "recursive_timed_mutex a second time";
157   traits::unlock(mutex);
158   traits::unlock(mutex);
159
160   lock_shared_or_unique(mutex);
161   gotLock = try_lock_shared_or_unique_for(mutex, std::chrono::milliseconds(10));
162   EXPECT_TRUE(gotLock) << "should have been able to acquire the "
163                        << "recursive_timed_mutex a second time";
164   unlock_shared_or_unique(mutex);
165   unlock_shared_or_unique(mutex);
166 }
167
168 TEST(LockTraits, boost_shared_mutex) {
169   using traits = LockTraits<boost::shared_mutex>;
170   static_assert(traits::is_timed, "boost::shared_mutex is a timed lock");
171   static_assert(traits::is_shared, "boost::shared_mutex is a shared lock");
172
173   boost::shared_mutex mutex;
174   traits::lock(mutex);
175   auto gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
176   EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
177                         << "shared_mutex a second time";
178   gotLock = traits::try_lock_shared_for(mutex, std::chrono::milliseconds(1));
179   EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
180                         << "shared_mutex a second time";
181   traits::unlock(mutex);
182
183   traits::lock_shared(mutex);
184   gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
185   EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
186                         << "shared_mutex a second time";
187   gotLock = traits::try_lock_shared_for(mutex, std::chrono::milliseconds(10));
188   EXPECT_TRUE(gotLock) << "should have been able to acquire the "
189                        << "shared_mutex a second time in shared mode";
190   traits::unlock_shared(mutex);
191   traits::unlock_shared(mutex);
192
193   lock_shared_or_unique(mutex);
194   gotLock = traits::try_lock_for(mutex, std::chrono::milliseconds(1));
195   EXPECT_FALSE(gotLock) << "should not have been able to acquire the "
196                         << "shared_mutex a second time";
197   gotLock = try_lock_shared_or_unique_for(mutex, std::chrono::milliseconds(10));
198   EXPECT_TRUE(gotLock) << "should have been able to acquire the "
199                        << "shared_mutex a second time in shared mode";
200   unlock_shared_or_unique(mutex);
201   unlock_shared_or_unique(mutex);
202 }
203 #endif // FOLLY_LOCK_TRAITS_HAVE_TIMED_MUTEXES