From 22e6055c75caa53a98f5a6b9887d67c3574888d6 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 28 Jun 2021 17:52:38 -0400 Subject: [PATCH] Googletest export Make multiple attempts to verify GetThreadCount() Testing GetThreadCount() is inheritently noisy, as other threads can be started or destroyed between two calls to GetThreadCount(). This is especially true under certain analyzer configurations, such as TSAN. PiperOrigin-RevId: 381951799 --- googletest/test/googletest-port-test.cc | 77 ++++++++++++++++--------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/googletest/test/googletest-port-test.cc b/googletest/test/googletest-port-test.cc index 2697355d..16d30c46 100644 --- a/googletest/test/googletest-port-test.cc +++ b/googletest/test/googletest-port-test.cc @@ -289,36 +289,61 @@ void* ThreadFunc(void* data) { } TEST(GetThreadCountTest, ReturnsCorrectValue) { - const size_t starting_count = GetThreadCount(); - pthread_t thread_id; + size_t starting_count; + size_t thread_count_after_create; + size_t thread_count_after_join; - internal::Mutex mutex; - { - internal::MutexLock lock(&mutex); - pthread_attr_t attr; - ASSERT_EQ(0, pthread_attr_init(&attr)); - ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + // We can't guarantee that no other thread was created or destroyed between + // any two calls to GetThreadCount(). We make multiple attempts, hoping that + // background noise is not constant and we would see the "right" values at + // some point. + for (int attempt = 0; attempt < 20; ++attempt) { + starting_count = GetThreadCount(); + pthread_t thread_id; - const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); - ASSERT_EQ(0, pthread_attr_destroy(&attr)); - ASSERT_EQ(0, status); - EXPECT_EQ(starting_count + 1, GetThreadCount()); + internal::Mutex mutex; + { + internal::MutexLock lock(&mutex); + pthread_attr_t attr; + ASSERT_EQ(0, pthread_attr_init(&attr)); + ASSERT_EQ(0, pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)); + + const int status = pthread_create(&thread_id, &attr, &ThreadFunc, &mutex); + ASSERT_EQ(0, pthread_attr_destroy(&attr)); + ASSERT_EQ(0, status); + } + + thread_count_after_create = GetThreadCount(); + + void* dummy; + ASSERT_EQ(0, pthread_join(thread_id, &dummy)); + + // Join before we decide whether we need to retry the test. Retry if an + // arbitrary other thread was created or destroyed in the meantime. + if (thread_count_after_create != starting_count + 1) continue; + + // The OS may not immediately report the updated thread count after + // joining a thread, causing flakiness in this test. To counter that, we + // wait for up to .5 seconds for the OS to report the correct value. + bool thread_count_matches = false; + for (int i = 0; i < 5; ++i) { + thread_count_after_join = GetThreadCount(); + if (thread_count_after_join == starting_count) { + thread_count_matches = true; + break; + } + + SleepMilliseconds(100); + } + + // Retry if an arbitrary other thread was created or destroyed. + if (!thread_count_matches) continue; + + break; } - void* dummy; - ASSERT_EQ(0, pthread_join(thread_id, &dummy)); - - // The OS may not immediately report the updated thread count after - // joining a thread, causing flakiness in this test. To counter that, we - // wait for up to .5 seconds for the OS to report the correct value. - for (int i = 0; i < 5; ++i) { - if (GetThreadCount() == starting_count) - break; - - SleepMilliseconds(100); - } - - EXPECT_EQ(starting_count, GetThreadCount()); + EXPECT_EQ(thread_count_after_create, starting_count + 1); + EXPECT_EQ(thread_count_after_join, starting_count); } #else TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) {