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 EXPECT_LT(waited, absl::Seconds(2));
112 }
113
TYPED_TEST_P(WaiterTest,WaitTimeWoken)114 TYPED_TEST_P(WaiterTest, WaitTimeWoken) {
115 absl::synchronization_internal::ThreadPool tp(1);
116 TypeParam waiter;
117 tp.Schedule([&]() {
118 // Include some `Poke()` calls to ensure they don't cause `waiter` to return
119 // from `Wait()`.
120 waiter.Poke();
121 absl::SleepFor(absl::Milliseconds(500));
122 waiter.Post();
123 });
124 absl::Time start = absl::Now();
125 EXPECT_TRUE(waiter.Wait(absl::synchronization_internal::KernelTimeout(
126 start + absl::Seconds(10))));
127 absl::Duration waited = absl::Now() - start;
128 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
129 EXPECT_LT(waited, absl::Seconds(2));
130 }
131
TYPED_TEST_P(WaiterTest,WaitDurationReached)132 TYPED_TEST_P(WaiterTest, WaitDurationReached) {
133 TypeParam waiter;
134 absl::Time start = absl::Now();
135 EXPECT_FALSE(waiter.Wait(
136 absl::synchronization_internal::KernelTimeout(absl::Milliseconds(500))));
137 absl::Duration waited = absl::Now() - start;
138 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
139 EXPECT_LT(waited, absl::Seconds(1));
140 }
141
TYPED_TEST_P(WaiterTest,WaitTimeReached)142 TYPED_TEST_P(WaiterTest, WaitTimeReached) {
143 TypeParam waiter;
144 absl::Time start = absl::Now();
145 EXPECT_FALSE(waiter.Wait(absl::synchronization_internal::KernelTimeout(
146 start + absl::Milliseconds(500))));
147 absl::Duration waited = absl::Now() - start;
148 EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500)));
149 EXPECT_LT(waited, absl::Seconds(1));
150 }
151
152 REGISTER_TYPED_TEST_SUITE_P(WaiterTest,
153 WaitNoTimeout,
154 WaitDurationWoken,
155 WaitTimeWoken,
156 WaitDurationReached,
157 WaitTimeReached);
158
159 #ifdef ABSL_INTERNAL_HAVE_FUTEX_WAITER
160 INSTANTIATE_TYPED_TEST_SUITE_P(Futex, WaiterTest,
161 absl::synchronization_internal::FutexWaiter);
162 #endif
163 #ifdef ABSL_INTERNAL_HAVE_PTHREAD_WAITER
164 INSTANTIATE_TYPED_TEST_SUITE_P(Pthread, WaiterTest,
165 absl::synchronization_internal::PthreadWaiter);
166 #endif
167 #ifdef ABSL_INTERNAL_HAVE_SEM_WAITER
168 INSTANTIATE_TYPED_TEST_SUITE_P(Sem, WaiterTest,
169 absl::synchronization_internal::SemWaiter);
170 #endif
171 #ifdef ABSL_INTERNAL_HAVE_WIN32_WAITER
172 INSTANTIATE_TYPED_TEST_SUITE_P(Win32, WaiterTest,
173 absl::synchronization_internal::Win32Waiter);
174 #endif
175 #ifdef ABSL_INTERNAL_HAVE_STDCPP_WAITER
176 INSTANTIATE_TYPED_TEST_SUITE_P(Stdcpp, WaiterTest,
177 absl::synchronization_internal::StdcppWaiter);
178 #endif
179
180 } // namespace
181