thread_identity_test.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright 2017 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. #include "absl/base/internal/thread_identity.h"
  15. #include <thread> // NOLINT(build/c++11)
  16. #include <vector>
  17. #include "gtest/gtest.h"
  18. #include "absl/base/attributes.h"
  19. #include "absl/base/internal/spinlock.h"
  20. #include "absl/base/macros.h"
  21. #include "absl/base/thread_annotations.h"
  22. #include "absl/synchronization/internal/per_thread_sem.h"
  23. #include "absl/synchronization/mutex.h"
  24. namespace absl {
  25. ABSL_NAMESPACE_BEGIN
  26. namespace base_internal {
  27. namespace {
  28. ABSL_CONST_INIT static absl::base_internal::SpinLock map_lock(
  29. absl::kConstInit, base_internal::SCHEDULE_KERNEL_ONLY);
  30. ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
  31. static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
  32. static void TestThreadIdentityCurrent(const void* assert_no_identity) {
  33. ThreadIdentity* identity;
  34. // We have to test this conditionally, because if the test framework relies
  35. // on Abseil, then some previous action may have already allocated an
  36. // identity.
  37. if (assert_no_identity == kCheckNoIdentity) {
  38. identity = CurrentThreadIdentityIfPresent();
  39. EXPECT_TRUE(identity == nullptr);
  40. }
  41. identity = synchronization_internal::GetOrCreateCurrentThreadIdentity();
  42. EXPECT_TRUE(identity != nullptr);
  43. ThreadIdentity* identity_no_init;
  44. identity_no_init = CurrentThreadIdentityIfPresent();
  45. EXPECT_TRUE(identity == identity_no_init);
  46. // Check that per_thread_synch is correctly aligned.
  47. EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
  48. PerThreadSynch::kAlignment);
  49. EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
  50. absl::base_internal::SpinLockHolder l(&map_lock);
  51. num_identities_reused++;
  52. }
  53. TEST(ThreadIdentityTest, BasicIdentityWorks) {
  54. // This tests for the main() thread.
  55. TestThreadIdentityCurrent(nullptr);
  56. }
  57. TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
  58. // Now try the same basic test with multiple threads being created and
  59. // destroyed. This makes sure that:
  60. // - New threads are created without a ThreadIdentity.
  61. // - We re-allocate ThreadIdentity objects from the free-list.
  62. // - If a thread implementation chooses to recycle threads, that
  63. // correct re-initialization occurs.
  64. static const int kNumLoops = 3;
  65. static const int kNumThreads = 32;
  66. for (int iter = 0; iter < kNumLoops; iter++) {
  67. std::vector<std::thread> threads;
  68. for (int i = 0; i < kNumThreads; ++i) {
  69. threads.push_back(
  70. std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
  71. }
  72. for (auto& thread : threads) {
  73. thread.join();
  74. }
  75. }
  76. // We should have recycled ThreadIdentity objects above; while (external)
  77. // library threads allocating their own identities may preclude some
  78. // reuse, we should have sufficient repetitions to exclude this.
  79. absl::base_internal::SpinLockHolder l(&map_lock);
  80. EXPECT_LT(kNumThreads, num_identities_reused);
  81. }
  82. TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
  83. // This test repeatly creates and joins a series of threads, each of
  84. // which acquires and releases shared Mutex locks. This verifies
  85. // Mutex operations work correctly under a reused
  86. // ThreadIdentity. Note that the most likely failure mode of this
  87. // test is a crash or deadlock.
  88. static const int kNumLoops = 10;
  89. static const int kNumThreads = 12;
  90. static const int kNumMutexes = 3;
  91. static const int kNumLockLoops = 5;
  92. Mutex mutexes[kNumMutexes];
  93. for (int iter = 0; iter < kNumLoops; ++iter) {
  94. std::vector<std::thread> threads;
  95. for (int thread = 0; thread < kNumThreads; ++thread) {
  96. threads.push_back(std::thread([&]() {
  97. for (int l = 0; l < kNumLockLoops; ++l) {
  98. for (int m = 0; m < kNumMutexes; ++m) {
  99. MutexLock lock(&mutexes[m]);
  100. }
  101. }
  102. }));
  103. }
  104. for (auto& thread : threads) {
  105. thread.join();
  106. }
  107. }
  108. }
  109. } // namespace
  110. } // namespace base_internal
  111. ABSL_NAMESPACE_END
  112. } // namespace absl