abseil-cpp/absl/base/internal/thread_identity_test.cc
Go to the documentation of this file.
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 
15 #include "absl/base/internal/thread_identity.h"
16 
17 #include <thread> // NOLINT(build/c++11)
18 #include <vector>
19 
20 #include "gtest/gtest.h"
21 #include "absl/base/attributes.h"
22 #include "absl/base/internal/spinlock.h"
23 #include "absl/base/macros.h"
24 #include "absl/base/thread_annotations.h"
25 #include "absl/synchronization/internal/per_thread_sem.h"
26 #include "absl/synchronization/mutex.h"
27 
28 namespace absl {
30 namespace base_internal {
31 namespace {
32 
35 ABSL_CONST_INIT static int num_identities_reused ABSL_GUARDED_BY(map_lock);
36 
37 static const void* const kCheckNoIdentity = reinterpret_cast<void*>(1);
38 
39 static void TestThreadIdentityCurrent(const void* assert_no_identity) {
40  ThreadIdentity* identity;
41 
42  // We have to test this conditionally, because if the test framework relies
43  // on Abseil, then some previous action may have already allocated an
44  // identity.
45  if (assert_no_identity == kCheckNoIdentity) {
46  identity = CurrentThreadIdentityIfPresent();
47  EXPECT_TRUE(identity == nullptr);
48  }
49 
51  EXPECT_TRUE(identity != nullptr);
52  ThreadIdentity* identity_no_init;
53  identity_no_init = CurrentThreadIdentityIfPresent();
54  EXPECT_TRUE(identity == identity_no_init);
55 
56  // Check that per_thread_synch is correctly aligned.
57  EXPECT_EQ(0, reinterpret_cast<intptr_t>(&identity->per_thread_synch) %
59  EXPECT_EQ(identity, identity->per_thread_synch.thread_identity());
60 
62  num_identities_reused++;
63 }
64 
65 TEST(ThreadIdentityTest, BasicIdentityWorks) {
66  // This tests for the main() thread.
67  TestThreadIdentityCurrent(nullptr);
68 }
69 
70 TEST(ThreadIdentityTest, BasicIdentityWorksThreaded) {
71  // Now try the same basic test with multiple threads being created and
72  // destroyed. This makes sure that:
73  // - New threads are created without a ThreadIdentity.
74  // - We re-allocate ThreadIdentity objects from the free-list.
75  // - If a thread implementation chooses to recycle threads, that
76  // correct re-initialization occurs.
77  static const int kNumLoops = 3;
78  static const int kNumThreads = 32;
79  for (int iter = 0; iter < kNumLoops; iter++) {
80  std::vector<std::thread> threads;
81  for (int i = 0; i < kNumThreads; ++i) {
82  threads.push_back(
83  std::thread(TestThreadIdentityCurrent, kCheckNoIdentity));
84  }
85  for (auto& thread : threads) {
86  thread.join();
87  }
88  }
89 
90  // We should have recycled ThreadIdentity objects above; while (external)
91  // library threads allocating their own identities may preclude some
92  // reuse, we should have sufficient repetitions to exclude this.
94  EXPECT_LT(kNumThreads, num_identities_reused);
95 }
96 
97 TEST(ThreadIdentityTest, ReusedThreadIdentityMutexTest) {
98  // This test repeatly creates and joins a series of threads, each of
99  // which acquires and releases shared Mutex locks. This verifies
100  // Mutex operations work correctly under a reused
101  // ThreadIdentity. Note that the most likely failure mode of this
102  // test is a crash or deadlock.
103  static const int kNumLoops = 10;
104  static const int kNumThreads = 12;
105  static const int kNumMutexes = 3;
106  static const int kNumLockLoops = 5;
107 
108  Mutex mutexes[kNumMutexes];
109  for (int iter = 0; iter < kNumLoops; ++iter) {
110  std::vector<std::thread> threads;
111  for (int thread = 0; thread < kNumThreads; ++thread) {
112  threads.push_back(std::thread([&]() {
113  for (int l = 0; l < kNumLockLoops; ++l) {
114  for (int m = 0; m < kNumMutexes; ++m) {
115  MutexLock lock(&mutexes[m]);
116  }
117  }
118  }));
119  }
120  for (auto& thread : threads) {
121  thread.join();
122  }
123  }
124 }
125 
126 } // namespace
127 } // namespace base_internal
129 } // namespace absl
absl::synchronization_internal::GetOrCreateCurrentThreadIdentity
base_internal::ThreadIdentity * GetOrCreateCurrentThreadIdentity()
Definition: abseil-cpp/absl/synchronization/internal/create_thread_identity.h:43
absl::base_internal::SpinLockHolder
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:196
MutexLock
#define MutexLock(x)
Definition: bloaty/third_party/re2/util/mutex.h:125
ABSL_CONST_INIT
#define ABSL_CONST_INIT
Definition: abseil-cpp/absl/base/attributes.h:716
absl::base_internal::SpinLock
Definition: third_party/abseil-cpp/absl/base/internal/spinlock.h:52
absl::kConstInit
@ kConstInit
Definition: abseil-cpp/absl/base/const_init.h:70
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
threads
static uv_thread_t * threads
Definition: threadpool.c:38
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
absl::base_internal::CurrentThreadIdentityIfPresent
ThreadIdentity * CurrentThreadIdentityIfPresent()
Definition: abseil-cpp/absl/base/internal/thread_identity.cc:128
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
intptr_t
_W64 signed int intptr_t
Definition: stdint-msvc2008.h:118
absl::base_internal::TEST
TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount)
Definition: bloaty/third_party/abseil-cpp/absl/base/internal/exponential_biased_test.cc:117
absl::base_internal::ABSL_GUARDED_BY
static ABSL_CONST_INIT std::vector< uint32_t > *tid_array ABSL_GUARDED_BY(tid_lock)
absl::base_internal::SCHEDULE_KERNEL_ONLY
@ SCHEDULE_KERNEL_ONLY
Definition: abseil-cpp/absl/base/internal/scheduling_mode.h:50
kNumThreads
const int kNumThreads
Definition: thread_stress_test.cc:46
google::protobuf.internal::Mutex
WrappedMutex Mutex
Definition: bloaty/third_party/protobuf/src/google/protobuf/stubs/mutex.h:113
EXPECT_LT
#define EXPECT_LT(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2032
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
iter
Definition: test_winkernel.cpp:47
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
run_grpclb_interop_tests.l
dictionary l
Definition: run_grpclb_interop_tests.py:410
regress.m
m
Definition: regress/regress.py:25
absl::base_internal::PerThreadSynch::kAlignment
static constexpr int kAlignment
Definition: abseil-cpp/absl/base/internal/thread_identity.h:56
thread
static uv_thread_t thread
Definition: test-async-null-cb.c:29
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:35