| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/synchronization/internal/waiter.h" |
|
|
| #include <ctime> |
| #include <iostream> |
| #include <ostream> |
|
|
| #include "absl/base/config.h" |
| #include "absl/random/random.h" |
| #include "absl/synchronization/internal/create_thread_identity.h" |
| #include "absl/synchronization/internal/futex_waiter.h" |
| #include "absl/synchronization/internal/kernel_timeout.h" |
| #include "absl/synchronization/internal/pthread_waiter.h" |
| #include "absl/synchronization/internal/sem_waiter.h" |
| #include "absl/synchronization/internal/stdcpp_waiter.h" |
| #include "absl/synchronization/internal/thread_pool.h" |
| #include "absl/synchronization/internal/win32_waiter.h" |
| #include "absl/time/clock.h" |
| #include "absl/time/time.h" |
| #include "gtest/gtest.h" |
|
|
| |
| |
| |
| #if defined(__GOOGLE_GRTE_VERSION__) && \ |
| !defined(ABSL_HAVE_ADDRESS_SANITIZER) && \ |
| !defined(ABSL_HAVE_MEMORY_SANITIZER) && \ |
| !defined(ABSL_HAVE_THREAD_SANITIZER) |
| extern "C" int __clock_gettime(clockid_t c, struct timespec* ts); |
|
|
| extern "C" int clock_gettime(clockid_t c, struct timespec* ts) { |
| if (c == CLOCK_MONOTONIC && |
| !absl::synchronization_internal::KernelTimeout::SupportsSteadyClock()) { |
| absl::SharedBitGen gen; |
| ts->tv_sec = absl::Uniform(gen, 0, 1'000'000'000); |
| ts->tv_nsec = absl::Uniform(gen, 0, 1'000'000'000); |
| return 0; |
| } |
| return __clock_gettime(c, ts); |
| } |
| #endif |
|
|
| namespace { |
|
|
| TEST(Waiter, PrintPlatformImplementation) { |
| |
| std::cout << absl::synchronization_internal::Waiter::kName << std::endl; |
| } |
|
|
| template <typename T> |
| class WaiterTest : public ::testing::Test { |
| public: |
| |
| |
| WaiterTest() { |
| absl::synchronization_internal::GetOrCreateCurrentThreadIdentity(); |
| } |
| }; |
|
|
| TYPED_TEST_SUITE_P(WaiterTest); |
|
|
| absl::Duration WithTolerance(absl::Duration d) { return d * 0.95; } |
|
|
| TYPED_TEST_P(WaiterTest, WaitNoTimeout) { |
| absl::synchronization_internal::ThreadPool tp(1); |
| TypeParam waiter; |
| tp.Schedule([&]() { |
| |
| |
| waiter.Poke(); |
| absl::SleepFor(absl::Seconds(1)); |
| waiter.Poke(); |
| absl::SleepFor(absl::Seconds(1)); |
| waiter.Post(); |
| }); |
| absl::Time start = absl::Now(); |
| EXPECT_TRUE( |
| waiter.Wait(absl::synchronization_internal::KernelTimeout::Never())); |
| absl::Duration waited = absl::Now() - start; |
| EXPECT_GE(waited, WithTolerance(absl::Seconds(2))); |
| } |
|
|
| TYPED_TEST_P(WaiterTest, WaitDurationWoken) { |
| absl::synchronization_internal::ThreadPool tp(1); |
| TypeParam waiter; |
| tp.Schedule([&]() { |
| |
| |
| waiter.Poke(); |
| absl::SleepFor(absl::Milliseconds(500)); |
| waiter.Post(); |
| }); |
| absl::Time start = absl::Now(); |
| EXPECT_TRUE(waiter.Wait( |
| absl::synchronization_internal::KernelTimeout(absl::Seconds(10)))); |
| absl::Duration waited = absl::Now() - start; |
| EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500))); |
| EXPECT_LT(waited, absl::Seconds(2)); |
| } |
|
|
| TYPED_TEST_P(WaiterTest, WaitTimeWoken) { |
| absl::synchronization_internal::ThreadPool tp(1); |
| TypeParam waiter; |
| tp.Schedule([&]() { |
| |
| |
| waiter.Poke(); |
| absl::SleepFor(absl::Milliseconds(500)); |
| waiter.Post(); |
| }); |
| absl::Time start = absl::Now(); |
| EXPECT_TRUE(waiter.Wait(absl::synchronization_internal::KernelTimeout( |
| start + absl::Seconds(10)))); |
| absl::Duration waited = absl::Now() - start; |
| EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500))); |
| EXPECT_LT(waited, absl::Seconds(2)); |
| } |
|
|
| TYPED_TEST_P(WaiterTest, WaitDurationReached) { |
| TypeParam waiter; |
| absl::Time start = absl::Now(); |
| EXPECT_FALSE(waiter.Wait( |
| absl::synchronization_internal::KernelTimeout(absl::Milliseconds(500)))); |
| absl::Duration waited = absl::Now() - start; |
| EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500))); |
| EXPECT_LT(waited, absl::Seconds(1)); |
| } |
|
|
| TYPED_TEST_P(WaiterTest, WaitTimeReached) { |
| TypeParam waiter; |
| absl::Time start = absl::Now(); |
| EXPECT_FALSE(waiter.Wait(absl::synchronization_internal::KernelTimeout( |
| start + absl::Milliseconds(500)))); |
| absl::Duration waited = absl::Now() - start; |
| EXPECT_GE(waited, WithTolerance(absl::Milliseconds(500))); |
| EXPECT_LT(waited, absl::Seconds(1)); |
| } |
|
|
| REGISTER_TYPED_TEST_SUITE_P(WaiterTest, |
| WaitNoTimeout, |
| WaitDurationWoken, |
| WaitTimeWoken, |
| WaitDurationReached, |
| WaitTimeReached); |
|
|
| #ifdef ABSL_INTERNAL_HAVE_FUTEX_WAITER |
| INSTANTIATE_TYPED_TEST_SUITE_P(Futex, WaiterTest, |
| absl::synchronization_internal::FutexWaiter); |
| #endif |
| #ifdef ABSL_INTERNAL_HAVE_PTHREAD_WAITER |
| INSTANTIATE_TYPED_TEST_SUITE_P(Pthread, WaiterTest, |
| absl::synchronization_internal::PthreadWaiter); |
| #endif |
| #ifdef ABSL_INTERNAL_HAVE_SEM_WAITER |
| INSTANTIATE_TYPED_TEST_SUITE_P(Sem, WaiterTest, |
| absl::synchronization_internal::SemWaiter); |
| #endif |
| #ifdef ABSL_INTERNAL_HAVE_WIN32_WAITER |
| INSTANTIATE_TYPED_TEST_SUITE_P(Win32, WaiterTest, |
| absl::synchronization_internal::Win32Waiter); |
| #endif |
| #ifdef ABSL_INTERNAL_HAVE_STDCPP_WAITER |
| INSTANTIATE_TYPED_TEST_SUITE_P(Stdcpp, WaiterTest, |
| absl::synchronization_internal::StdcppWaiter); |
| #endif |
|
|
| } |
|
|