xref: /aosp_15_r20/external/abseil-cpp/absl/synchronization/internal/waiter_test.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
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