waiter_test.cc (6529B)
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 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 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. 68 WaiterTest() { 69 absl::synchronization_internal::GetOrCreateCurrentThreadIdentity(); 70 } 71 }; 72 73 TYPED_TEST_SUITE_P(WaiterTest); 74 75 absl::Duration WithTolerance(absl::Duration d) { return d * 0.95; } 76 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 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 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 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 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