1 // Copyright 2023 The Abseil Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/synchronization/internal/waiter.h"
16
17 #include <ctime>
18 #include <iostream>
19 #include <ostream>
20
21 #include "absl/base/config.h"
22 #include "absl/random/random.h"
23 #include "absl/synchronization/internal/create_thread_identity.h"
24 #include "absl/synchronization/internal/futex_waiter.h"
25 #include "absl/synchronization/internal/kernel_timeout.h"
26 #include "absl/synchronization/internal/pthread_waiter.h"
27 #include "absl/synchronization/internal/sem_waiter.h"
28 #include "absl/synchronization/internal/stdcpp_waiter.h"
29 #include "absl/synchronization/internal/thread_pool.h"
30 #include "absl/synchronization/internal/win32_waiter.h"
31 #include "absl/time/clock.h"
32 #include "absl/time/time.h"
33 #include "gtest/gtest.h"
34
35 // Test go/btm support by randomizing the value of clock_gettime() for
36 // CLOCK_MONOTONIC. This works by overriding a weak symbol in glibc.
37 // We should be resistant to this randomization when !SupportsSteadyClock().
38 #if defined(__GOOGLE_GRTE_VERSION__) && \
39 !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
40 !defined(ABSL_HAVE_MEMORY_SANITIZER) && \
41 !defined(ABSL_HAVE_THREAD_SANITIZER)
42 extern "C" int __clock_gettime(clockid_t c, struct timespec* ts);
43
clock_gettime(clockid_t c,struct timespec * ts)44 extern "C" int clock_gettime(clockid_t c, struct timespec* ts) {
45 if (c == CLOCK_MONOTONIC &&
46 !absl::synchronization_internal::KernelTimeout::SupportsSteadyClock()) {
47 thread_local absl::BitGen gen; // NOLINT
48 ts->tv_sec = absl::Uniform(gen, 0, 1'000'000'000);
49 ts->tv_nsec = absl::Uniform(gen, 0, 1'000'000'000);
50 return 0;
51 }
52 return __clock_gettime(c, ts);
53 }
54 #endif
55
56 namespace {
57
TEST(Waiter,PrintPlatformImplementation)58 TEST(Waiter, PrintPlatformImplementation) {
59 // Allows us to verify that the platform is using the expected implementation.
60 std::cout << absl::synchronization_internal::Waiter::kName << std::endl;
61 }
62
63 template <typename T>
64 class WaiterTest : public ::testing::Test {
65 public:
66 // Waiter implementations assume that a ThreadIdentity has already been
67 // created.
WaiterTest()68 WaiterTest() {
69 absl::synchronization_internal::GetOrCreateCurrentThreadIdentity();
70 }
71 };
72
73 TYPED_TEST_SUITE_P(WaiterTest);
74
WithTolerance(absl::Duration d)75 absl::Duration WithTolerance(absl::Duration d) { return d * 0.95; }
76
TYPED_TEST_P(WaiterTest,WaitNoTimeout)77 TYPED_TEST_P(WaiterTest, WaitNoTimeout) {
78 absl::synchronization_internal::ThreadPool tp(1);
79 TypeParam waiter;
80 tp.Schedule([&]() {
81 // Include some `Poke()` calls to ensure they don't cause `waiter` to return
82 // from `Wait()`.
83 waiter.Poke();
84 absl::SleepFor(absl::Seconds(1));
85 waiter.Poke();
86 absl::SleepFor(absl::Seconds(1));
87 waiter.Post();
88 });
89 absl::Time start = absl::Now();
90 EXPECT_TRUE(
91 waiter.Wait(absl::synchronization_internal::KernelTimeout::Never()));
92 absl::Duration waited = absl::Now() - start;
93 EXPECT_GE(waited, WithTolerance(absl::Seconds(2)));
94 }
95
TYPED_TEST_P(WaiterTest,WaitDurationWoken)96 TYPED_TEST_P(WaiterTest, WaitDurationWoken) {
97 absl::synchronization_internal::ThreadPool tp(1);
98 TypeParam waiter;
99 tp.Schedule([&]() {
100 // Include some `Poke()` calls to ensure they don't cause `waiter` to return
101 // from `Wait()`.
102 waiter.Poke();
103 absl::SleepFor(absl::Milliseconds(500));
104 waiter.Post();
105 });
106 absl::Time start = absl::Now();
107 EXPECT_TRUE(waiter.Wait(
108 absl::synchronization_internal::KernelTimeout(absl::Seconds(10))));
109 absl::Duration waited = absl::Now() - start;
110 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
111 #ifndef _MSC_VER
112 // Skip on MSVC due to flakiness.
113 EXPECT_LT(waited, absl::Seconds(2));
114 #endif
115 }
116
TYPED_TEST_P(WaiterTest,WaitTimeWoken)117 TYPED_TEST_P(WaiterTest, WaitTimeWoken) {
118 absl::synchronization_internal::ThreadPool tp(1);
119 TypeParam waiter;
120 tp.Schedule([&]() {
121 // Include some `Poke()` calls to ensure they don't cause `waiter` to return
122 // from `Wait()`.
123 waiter.Poke();
124 absl::SleepFor(absl::Milliseconds(500));
125 waiter.Post();
126 });
127 absl::Time start = absl::Now();
128 EXPECT_TRUE(waiter.Wait(absl::synchronization_internal::KernelTimeout(
129 start + absl::Seconds(10))));
130 absl::Duration waited = absl::Now() - start;
131 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
132 EXPECT_LT(waited, absl::Seconds(2));
133 }
134
TYPED_TEST_P(WaiterTest,WaitDurationReached)135 TYPED_TEST_P(WaiterTest, WaitDurationReached) {
136 TypeParam waiter;
137 absl::Time start = absl::Now();
138 EXPECT_FALSE(waiter.Wait(
139 absl::synchronization_internal::KernelTimeout(absl::Milliseconds(500))));
140 absl::Duration waited = absl::Now() - start;
141 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
142 EXPECT_LT(waited, absl::Seconds(1));
143 }
144
TYPED_TEST_P(WaiterTest,WaitTimeReached)145 TYPED_TEST_P(WaiterTest, WaitTimeReached) {
146 TypeParam waiter;
147 absl::Time start = absl::Now();
148 EXPECT_FALSE(waiter.Wait(absl::synchronization_internal::KernelTimeout(
149 start + absl::Milliseconds(500))));
150 absl::Duration waited = absl::Now() - start;
151 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
152 EXPECT_LT(waited, absl::Seconds(1));
153 }
154
155 REGISTER_TYPED_TEST_SUITE_P(WaiterTest,
156 WaitNoTimeout,
157 WaitDurationWoken,
158 WaitTimeWoken,
159 WaitDurationReached,
160 WaitTimeReached);
161
162 #ifdef ABSL_INTERNAL_HAVE_FUTEX_WAITER
163 INSTANTIATE_TYPED_TEST_SUITE_P(Futex, WaiterTest,
164 absl::synchronization_internal::FutexWaiter);
165 #endif
166 #ifdef ABSL_INTERNAL_HAVE_PTHREAD_WAITER
167 INSTANTIATE_TYPED_TEST_SUITE_P(Pthread, WaiterTest,
168 absl::synchronization_internal::PthreadWaiter);
169 #endif
170 #ifdef ABSL_INTERNAL_HAVE_SEM_WAITER
171 INSTANTIATE_TYPED_TEST_SUITE_P(Sem, WaiterTest,
172 absl::synchronization_internal::SemWaiter);
173 #endif
174 #ifdef ABSL_INTERNAL_HAVE_WIN32_WAITER
175 INSTANTIATE_TYPED_TEST_SUITE_P(Win32, WaiterTest,
176 absl::synchronization_internal::Win32Waiter);
177 #endif
178 #ifdef ABSL_INTERNAL_HAVE_STDCPP_WAITER
179 INSTANTIATE_TYPED_TEST_SUITE_P(Stdcpp, WaiterTest,
180 absl::synchronization_internal::StdcppWaiter);
181 #endif
182
183 } // namespace
184