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 #include <folly/SmallLocks.h>
19 #include <folly/Random.h>
31 #include <gtest/gtest.h>
34 using folly::MicroSpinLock;
35 using folly::PicoSpinLock;
36 using folly::MSLGuard;
46 memset(ar, 0, sizeof ar);
50 // Compile time test for packed struct support (requires that both of
51 // these classes are POD).
53 struct ignore1 { MicroSpinLock msl; int16_t foo; } FOLLY_PACK_ATTR;
54 struct ignore2 { PicoSpinLock<uint32_t> psl; int16_t foo; } FOLLY_PACK_ATTR;
55 static_assert(sizeof(ignore1) == 3, "Size check failed");
56 static_assert(sizeof(ignore2) == 6, "Size check failed");
57 static_assert(sizeof(MicroSpinLock) == 1, "Size check failed");
64 auto rng = folly::ThreadLocalPRNG();
65 for (int i = 0; i < max; i++) {
70 for (size_t i = 1; i < sizeof v.ar / sizeof i; ++i) {
71 EXPECT_EQ(first, v.ar[i]);
74 int byte = folly::Random::rand32(rng);
75 memset(v.ar, char(byte), sizeof v.ar);
79 template<class T> struct PslTest {
82 PslTest() { lock.init(); }
85 T ourVal = rand() % (T(1) << (sizeof(T) * 8 - 1));
86 for (int i = 0; i < 10000; ++i) {
87 std::lock_guard<PicoSpinLock<T>> guard(lock);
89 for (int n = 0; n < 10; ++n) {
90 folly::asm_volatile_pause();
91 EXPECT_EQ(lock.getData(), ourVal);
101 const int nthrs = 17;
102 std::vector<std::thread> threads;
103 for (int i = 0; i < nthrs; ++i) {
104 threads.push_back(std::thread(&PslTest<T>::doTest, &testObj));
106 for (auto& t : threads) {
117 std::lock_guard<MicroSpinLock> g(lock_);
118 // This bug depends on gcc register allocation and is very sensitive. We
119 // have to use DCHECK instead of EXPECT_*.
120 DCHECK(!lock_.try_lock());
129 TEST(SmallLocks, SpinLockCorrectness) {
130 EXPECT_EQ(sizeof(MicroSpinLock), 1);
132 int nthrs = sysconf(_SC_NPROCESSORS_ONLN) * 2;
133 std::vector<std::thread> threads;
134 for (int i = 0; i < nthrs; ++i) {
135 threads.push_back(std::thread(splock_test));
137 for (auto& t : threads) {
142 TEST(SmallLocks, PicoSpinCorrectness) {
143 doPslTest<int16_t>();
144 doPslTest<uint16_t>();
145 doPslTest<int32_t>();
146 doPslTest<uint32_t>();
147 doPslTest<int64_t>();
148 doPslTest<uint64_t>();
151 TEST(SmallLocks, PicoSpinSigned) {
152 typedef PicoSpinLock<int16_t,0> Lock;
155 EXPECT_EQ(val.getData(), -4);
158 std::lock_guard<Lock> guard(val);
159 EXPECT_EQ(val.getData(), -4);
161 EXPECT_EQ(val.getData(), -8);
163 EXPECT_EQ(val.getData(), -8);
166 TEST(SmallLocks, RegClobber) {