25 #include "gtest/gtest.h" 39 namespace base_internal {
45 int64_t wait_end_time) {
55 static constexpr
int kArrayLength = 10;
56 static uint32_t values[kArrayLength];
59 static SpinLock static_cooperative_spinlock(
62 static SpinLock static_noncooperative_spinlock(
68 static uint32_t Hash32(uint32_t
a, uint32_t c) {
69 uint32_t
b = 0x9e3779b9UL;
70 a -=
b; a -= c; a ^= (c >> 13);
71 b -= c; b -=
a; b ^= (a << 8);
72 c -=
a; c -=
b; c ^= (b >> 13);
73 a -=
b; a -= c; a ^= (c >> 12);
74 b -= c; b -=
a; b ^= (a << 16);
75 c -=
a; c -=
b; c ^= (b >> 5);
76 a -=
b; a -= c; a ^= (c >> 3);
77 b -= c; b -=
a; b ^= (a << 10);
78 c -=
a; c -=
b; c ^= (b >> 15);
82 static void TestFunction(
int thread_salt,
SpinLock* spinlock) {
85 for (
int j = 0; j < kArrayLength; j++) {
86 const int index = (j + thread_salt) % kArrayLength;
87 values[index] = Hash32(values[index], thread_salt);
88 std::this_thread::yield();
93 static void ThreadedTest(
SpinLock* spinlock) {
94 std::vector<std::thread> threads;
96 threads.push_back(std::thread(TestFunction,
i, spinlock));
98 for (
auto& thread : threads) {
103 for (
int i = 1;
i < kArrayLength;
i++) {
104 EXPECT_EQ(values[0], values[
i]);
115 TEST(
SpinLock, StaticNonCooperativeDisablesScheduling) {
116 static_noncooperative_spinlock.
Lock();
118 static_noncooperative_spinlock.
Unlock();
123 const int kProfileTimestampShift = 7;
124 const int kLockwordReservedShift = 3;
125 const uint32_t kSpinLockSleeper = 8;
129 const int kMaxCyclesShift =
130 32 - kLockwordReservedShift + kProfileTimestampShift;
131 const uint64_t kMaxCycles = (int64_t{1} << kMaxCyclesShift) - 1;
134 const uint32_t kLockwordReservedMask = (1 << kLockwordReservedShift) - 1;
137 const uint64_t kProfileTimestampMask = (1 << kProfileTimestampShift) - 1;
140 std::default_random_engine generator;
142 std::uniform_int_distribution<uint64_t> time_distribution(
143 0, std::numeric_limits<uint64_t>::max() >> 4);
144 std::uniform_int_distribution<uint64_t> cycle_distribution(0, kMaxCycles);
146 for (
int i = 0;
i < 100;
i++) {
147 int64_t start_time = time_distribution(generator);
148 int64_t cycles = cycle_distribution(generator);
149 int64_t end_time = start_time + cycles;
151 EXPECT_EQ(0, lock_value & kLockwordReservedMask);
153 EXPECT_EQ(0, decoded & kProfileTimestampMask);
154 EXPECT_EQ(cycles & ~kProfileTimestampMask, decoded);
158 int64_t start_time = time_distribution(generator);
159 EXPECT_EQ(kSpinLockSleeper,
163 EXPECT_EQ(kMaxCycles & ~kProfileTimestampMask,
167 int64_t sleeper_cycles =
168 kSpinLockSleeper << (kProfileTimestampShift - kLockwordReservedShift);
169 uint32_t sleeper_value =
171 EXPECT_NE(sleeper_value, kSpinLockSleeper);
177 uint64_t expected_max_value_decoded = kMaxCycles & ~kProfileTimestampMask;
178 EXPECT_EQ(expected_max_value_decoded, max_value_decoded);
180 const int64_t
step = (1 << kProfileTimestampShift);
181 uint32_t after_max_value =
183 uint64_t after_max_value_decoded =
185 EXPECT_EQ(expected_max_value_decoded, after_max_value_decoded);
188 start_time, start_time + kMaxCycles - step);
189 uint64_t before_max_value_decoded =
191 EXPECT_GT(expected_max_value_decoded, before_max_value_decoded);
194 TEST(SpinLockWithThreads, StaticSpinLock) {
195 ThreadedTest(&static_spinlock);
197 TEST(SpinLockWithThreads, StackSpinLock) {
199 ThreadedTest(&spinlock);
202 TEST(SpinLockWithThreads, StackCooperativeSpinLock) {
204 ThreadedTest(&spinlock);
207 TEST(SpinLockWithThreads, StackNonCooperativeSpinLock) {
209 ThreadedTest(&spinlock);
212 TEST(SpinLockWithThreads, StaticCooperativeSpinLock) {
213 ThreadedTest(&static_cooperative_spinlock);
216 TEST(SpinLockWithThreads, StaticNonCooperativeSpinLock) {
217 ThreadedTest(&static_noncooperative_spinlock);
220 TEST(SpinLockWithThreads, DoesNotDeadlock) {
236 static void DeadlockTest(
SpinLock* spinlock,
int num_spinners) {
239 std::vector<std::thread> threads;
242 std::thread(Helper::LockThenWait, &locked, spinlock, &counter));
243 for (
int i = 0;
i < num_spinners; ++
i) {
245 std::thread(Helper::NotifyThenLock, &locked, spinlock, &counter));
248 for (
auto& thread : threads) {
254 SpinLock stack_cooperative_spinlock(
257 Helper::DeadlockTest(&stack_cooperative_spinlock,
259 Helper::DeadlockTest(&stack_noncooperative_spinlock,
261 Helper::DeadlockTest(&static_cooperative_spinlock,
263 Helper::DeadlockTest(&static_noncooperative_spinlock,
static bool ReschedulingIsAllowed()
void Lock() EXCLUSIVE_LOCK_FUNCTION()
TEST(NotificationTest, SanityTest)
static uint32_t EncodeWaitCycles(int64_t wait_start_time, int64_t wait_end_time)
void Unlock() UNLOCK_FUNCTION()
CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept
static uint64_t DecodeWaitCycles(uint32_t lock_value)
void WaitForNotification() const
static uint64_t DecodeWaitCycles(uint32_t lock_value)
static uint32_t EncodeWaitCycles(int64_t wait_start_time, int64_t wait_end_time)
constexpr int32_t kNumThreads