1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/allocator/dispatcher/tls.h"
6
7 #include <string_view>
8
9 #if USE_LOCAL_TLS_EMULATION()
10 #include <algorithm>
11 #include <array>
12 #include <cstddef>
13 #include <functional>
14 #include <list>
15 #include <mutex>
16 #include <thread>
17 #include <unordered_set>
18 #include <utility>
19 #include <vector>
20
21 #include "base/debug/crash_logging.h"
22 #include "base/strings/stringprintf.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using ::testing::_;
27 using ::testing::InSequence;
28 using ::testing::NiceMock;
29 using ::testing::NotNull;
30 using ::testing::Return;
31 using ::testing::ReturnNull;
32
33 namespace base::allocator::dispatcher {
34 namespace {
35 struct DataToStore {
36 int data_int = 0;
37 float data_float = 0.0;
38 size_t data_size_t = 0;
39 double data_double = 0.0;
40 };
41
42 struct AllocatorMockBase {
AllocatorMockBasebase::allocator::dispatcher::__anoncefca7370111::AllocatorMockBase43 AllocatorMockBase() {
44 ON_CALL(*this, AllocateMemory(_)).WillByDefault([](size_t size_in_bytes) {
45 return malloc(size_in_bytes);
46 });
47 ON_CALL(*this, FreeMemoryForTesting(_, _))
48 .WillByDefault([](void* pointer_to_allocated, size_t size_in_bytes) {
49 free(pointer_to_allocated);
50 return true;
51 });
52 }
53
54 MOCK_METHOD(void*, AllocateMemory, (size_t size_in_bytes), ());
55 MOCK_METHOD(bool,
56 FreeMemoryForTesting,
57 (void* pointer_to_allocated, size_t size_in_bytes),
58 ());
59 };
60
61 struct TLSSystemMockBase {
TLSSystemMockBasebase::allocator::dispatcher::__anoncefca7370111::TLSSystemMockBase62 TLSSystemMockBase() {
63 ON_CALL(*this, Setup(_, _)).WillByDefault(Return(true));
64 ON_CALL(*this, TearDownForTesting()).WillByDefault(Return(true));
65 ON_CALL(*this, SetThreadSpecificData(_)).WillByDefault(Return(true));
66 }
67
68 MOCK_METHOD(
69 bool,
70 Setup,
71 (internal::OnThreadTerminationFunction thread_termination_function,
72 const std::string_view instance_id),
73 ());
74 MOCK_METHOD(bool, TearDownForTesting, (), ());
75 MOCK_METHOD(void*, GetThreadSpecificData, (), ());
76 MOCK_METHOD(bool, SetThreadSpecificData, (void* data), ());
77 };
78
79 struct CrashKeyImplementationMockBase
80 : public base::debug::CrashKeyImplementation {
81 MOCK_METHOD(base::debug::CrashKeyString*,
82 Allocate,
83 (const char name[], base::debug::CrashKeySize size),
84 (override));
85 MOCK_METHOD(void,
86 Set,
87 (base::debug::CrashKeyString * crash_key, std::string_view value),
88 (override));
89 MOCK_METHOD(void,
90 Clear,
91 (base::debug::CrashKeyString * crash_key),
92 (override));
93 MOCK_METHOD(void, OutputCrashKeysToStream, (std::ostream & out), (override));
94 };
95
96 using AllocatorMock = NiceMock<AllocatorMockBase>;
97 using TLSSystemMock = NiceMock<TLSSystemMockBase>;
98 using CrashKeyImplementationMock = NiceMock<CrashKeyImplementationMockBase>;
99
100 template <typename T, typename Allocator, typename TLSSystem>
CreateThreadLocalStorage(Allocator & allocator,TLSSystem & tlsSystem)101 auto CreateThreadLocalStorage(Allocator& allocator, TLSSystem& tlsSystem) {
102 return ThreadLocalStorage<T, std::reference_wrapper<Allocator>,
103 std::reference_wrapper<TLSSystem>, 0, true>(
104 "ThreadLocalStorage", std::ref(allocator), std::ref(tlsSystem));
105 }
106
107 template <typename T>
CreateThreadLocalStorage()108 auto CreateThreadLocalStorage() {
109 return ThreadLocalStorage<T, internal::DefaultAllocator,
110 internal::DefaultTLSSystem, 0, true>(
111 "ThreadLocalStorage");
112 }
113
114 } // namespace
115
116 struct BaseThreadLocalStorageTest : public ::testing::Test {};
117
TEST_F(BaseThreadLocalStorageTest,VerifyDataIsIndependentBetweenDifferentSUTs)118 TEST_F(BaseThreadLocalStorageTest,
119 VerifyDataIsIndependentBetweenDifferentSUTs) {
120 auto sut_1 = CreateThreadLocalStorage<DataToStore>();
121 auto sut_2 = CreateThreadLocalStorage<DataToStore>();
122
123 EXPECT_NE(sut_1.GetThreadLocalData(), sut_2.GetThreadLocalData());
124 }
125
TEST_F(BaseThreadLocalStorageTest,VerifyDistinctEntriesForEachThread)126 TEST_F(BaseThreadLocalStorageTest, VerifyDistinctEntriesForEachThread) {
127 auto sut = CreateThreadLocalStorage<DataToStore>();
128 using TLSType = decltype(sut);
129
130 std::array<std::thread, 2 * TLSType::ItemsPerChunk> threads;
131 std::mutex thread_worker_mutex;
132 std::condition_variable thread_counter_cv;
133 std::atomic_uint32_t thread_counter{0};
134 std::unordered_set<void*> stored_object_addresses;
135
136 std::mutex threads_can_finish_mutex;
137 std::condition_variable threads_can_finish_cv;
138 std::atomic_bool threads_can_finish{false};
139
140 for (auto& t : threads) {
141 t = std::thread{[&] {
142 {
143 std::lock_guard<std::mutex> lock(thread_worker_mutex);
144 stored_object_addresses.insert(sut.GetThreadLocalData());
145 ++thread_counter;
146 thread_counter_cv.notify_one();
147 }
148
149 {
150 std::unique_lock<std::mutex> lock(threads_can_finish_mutex);
151 threads_can_finish_cv.wait(lock,
152 [&] { return threads_can_finish.load(); });
153 }
154 }};
155 }
156
157 {
158 std::unique_lock<std::mutex> lock(thread_worker_mutex);
159 thread_counter_cv.wait(
160 lock, [&] { return thread_counter.load() == threads.size(); });
161 }
162
163 {
164 std::unique_lock<std::mutex> lock(threads_can_finish_mutex);
165 threads_can_finish = true;
166 threads_can_finish_cv.notify_all();
167 }
168
169 for (auto& t : threads) {
170 t.join();
171 }
172
173 EXPECT_EQ(stored_object_addresses.size(), threads.size());
174 }
175
TEST_F(BaseThreadLocalStorageTest,VerifyEntriesAreReusedForNewThreads)176 TEST_F(BaseThreadLocalStorageTest, VerifyEntriesAreReusedForNewThreads) {
177 auto sut = CreateThreadLocalStorage<DataToStore>();
178 using TLSType = decltype(sut);
179
180 std::unordered_set<void*> stored_object_addresses;
181
182 for (size_t thread_count = 0; thread_count < (2 * TLSType::ItemsPerChunk);
183 ++thread_count) {
184 auto thread = std::thread{
185 [&] { stored_object_addresses.insert(sut.GetThreadLocalData()); }};
186
187 thread.join();
188 }
189
190 EXPECT_EQ(stored_object_addresses.size(), 1ul);
191 }
192
TEST_F(BaseThreadLocalStorageTest,VerifyDataIsSameWithinEachThread)193 TEST_F(BaseThreadLocalStorageTest, VerifyDataIsSameWithinEachThread) {
194 auto sut = CreateThreadLocalStorage<DataToStore>();
195 using TLSType = decltype(sut);
196
197 std::array<std::thread, 2 * TLSType::ItemsPerChunk> threads;
198
199 for (auto& t : threads) {
200 t = std::thread{[&] {
201 EXPECT_EQ(sut.GetThreadLocalData(), sut.GetThreadLocalData());
202 std::this_thread::sleep_for(std::chrono::milliseconds(100));
203 // Check once again to verify the data doesn't change in the course of a
204 // thread's lifetime.
205 EXPECT_EQ(sut.GetThreadLocalData(), sut.GetThreadLocalData());
206 }};
207 }
208
209 for (auto& t : threads) {
210 t.join();
211 }
212 }
213
TEST_F(BaseThreadLocalStorageTest,VerifySetupTeardownSequence)214 TEST_F(BaseThreadLocalStorageTest, VerifySetupTeardownSequence) {
215 AllocatorMock allocator_mock;
216 TLSSystemMock tlsSystem_mock;
217
218 InSequence execution_sequence;
219
220 EXPECT_CALL(allocator_mock, AllocateMemory(_))
221 .WillOnce([](size_t size_in_bytes) { return malloc(size_in_bytes); });
222 EXPECT_CALL(tlsSystem_mock, Setup(NotNull(), _)).WillOnce(Return(true));
223 EXPECT_CALL(tlsSystem_mock, TearDownForTesting()).WillOnce(Return(true));
224 EXPECT_CALL(allocator_mock, FreeMemoryForTesting(_, _))
225 .WillOnce([](void* pointer_to_allocated, size_t size_in_bytes) {
226 free(pointer_to_allocated);
227 return true;
228 });
229
230 auto sut =
231 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
232 }
233
TEST_F(BaseThreadLocalStorageTest,VerifyAllocatorIsUsed)234 TEST_F(BaseThreadLocalStorageTest, VerifyAllocatorIsUsed) {
235 AllocatorMock allocator_mock;
236 TLSSystemMock tlsSystem_mock;
237
238 EXPECT_CALL(allocator_mock, AllocateMemory(_))
239 .WillOnce([](size_t size_in_bytes) { return malloc(size_in_bytes); });
240
241 EXPECT_CALL(allocator_mock, FreeMemoryForTesting(_, _))
242 .WillOnce([](void* pointer_to_allocated, size_t size_in_bytes) {
243 free(pointer_to_allocated);
244 return true;
245 });
246
247 auto sut =
248 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
249 }
250
TEST_F(BaseThreadLocalStorageTest,VerifyAllocatorIsUsedForMultipleChunks)251 TEST_F(BaseThreadLocalStorageTest, VerifyAllocatorIsUsedForMultipleChunks) {
252 AllocatorMock allocator_mock;
253 TLSSystemMock tlsSystem_mock;
254
255 constexpr auto number_of_chunks = 3;
256
257 EXPECT_CALL(allocator_mock, AllocateMemory(_))
258 .Times(number_of_chunks)
259 .WillRepeatedly(
260 [](size_t size_in_bytes) { return malloc(size_in_bytes); });
261
262 EXPECT_CALL(allocator_mock, FreeMemoryForTesting(_, _))
263 .Times(number_of_chunks)
264 .WillRepeatedly([](void* pointer_to_allocated, size_t size_in_bytes) {
265 free(pointer_to_allocated);
266 return true;
267 });
268
269 auto sut =
270 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
271
272 std::array<std::thread,
273 (number_of_chunks - 1) * decltype(sut)::ItemsPerChunk + 1>
274 threads;
275 std::mutex thread_worker_mutex;
276 std::condition_variable thread_counter_cv;
277 std::atomic_uint32_t thread_counter{0};
278 std::unordered_set<void*> stored_object_addresses;
279
280 std::mutex threads_can_finish_mutex;
281 std::condition_variable threads_can_finish_cv;
282 std::atomic_bool threads_can_finish{false};
283
284 for (auto& t : threads) {
285 t = std::thread{[&] {
286 sut.GetThreadLocalData();
287
288 {
289 std::lock_guard<std::mutex> lock(thread_worker_mutex);
290 ++thread_counter;
291 thread_counter_cv.notify_one();
292 }
293
294 {
295 std::unique_lock<std::mutex> lock(threads_can_finish_mutex);
296 threads_can_finish_cv.wait(lock,
297 [&] { return threads_can_finish.load(); });
298 }
299 }};
300 }
301
302 {
303 std::unique_lock<std::mutex> lock(thread_worker_mutex);
304 thread_counter_cv.wait(
305 lock, [&] { return thread_counter.load() == threads.size(); });
306 }
307
308 {
309 std::unique_lock<std::mutex> lock(threads_can_finish_mutex);
310 threads_can_finish = true;
311 threads_can_finish_cv.notify_all();
312 }
313
314 for (auto& t : threads) {
315 t.join();
316 }
317 }
318
TEST_F(BaseThreadLocalStorageTest,VerifyTLSSystemIsUsed)319 TEST_F(BaseThreadLocalStorageTest, VerifyTLSSystemIsUsed) {
320 AllocatorMock allocator_mock;
321 TLSSystemMock tlsSystem_mock;
322
323 InSequence execution_sequence;
324
325 EXPECT_CALL(tlsSystem_mock, Setup(NotNull(), _)).WillOnce(Return(true));
326 EXPECT_CALL(tlsSystem_mock, GetThreadSpecificData())
327 .WillOnce(Return(nullptr));
328 EXPECT_CALL(tlsSystem_mock, SetThreadSpecificData(NotNull()));
329 EXPECT_CALL(tlsSystem_mock, TearDownForTesting())
330 .Times(1)
331 .WillOnce(Return(true));
332
333 auto sut =
334 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
335
336 sut.GetThreadLocalData();
337 }
338
339 #if defined(GTEST_HAS_DEATH_TEST)
340 struct BaseThreadLocalStorageDeathTest : public ::testing::Test {};
341
TEST_F(BaseThreadLocalStorageDeathTest,VerifyDeathIfAllocationFails)342 TEST_F(BaseThreadLocalStorageDeathTest, VerifyDeathIfAllocationFails) {
343 auto f = [] {
344 AllocatorMock allocator_mock;
345 TLSSystemMock tlsSystem_mock;
346
347 // Setup all expectations here. If we're setting them up in the parent
348 // process, they will fail because the parent doesn't execute any test.
349 EXPECT_CALL(allocator_mock, AllocateMemory(_)).WillOnce(ReturnNull());
350
351 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
352 };
353
354 EXPECT_DEATH(f(), "");
355 }
356
TEST_F(BaseThreadLocalStorageDeathTest,VerifyDeathIfFreeFails)357 TEST_F(BaseThreadLocalStorageDeathTest, VerifyDeathIfFreeFails) {
358 auto f = [] {
359 AllocatorMock allocator_mock;
360 TLSSystemMock tlsSystem_mock;
361
362 // Setup all expectations here. If we're setting them up in the parent
363 // process, they will fail because the parent doesn't execute any test.
364 EXPECT_CALL(allocator_mock, FreeMemoryForTesting(_, _))
365 .WillOnce([](void* allocated_memory, size_t size_in_bytes) {
366 free(allocated_memory);
367 return false;
368 });
369
370 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
371 };
372
373 EXPECT_DEATH(f(), "");
374 }
375
TEST_F(BaseThreadLocalStorageDeathTest,VerifyDeathIfTLSSetupFails)376 TEST_F(BaseThreadLocalStorageDeathTest, VerifyDeathIfTLSSetupFails) {
377 auto f = [] {
378 AllocatorMock allocator_mock;
379 TLSSystemMock tlsSystem_mock;
380
381 // Setup all expectations here. If we're setting them up in the parent
382 // process, they will fail because the parent doesn't execute any test.
383 EXPECT_CALL(tlsSystem_mock, Setup(_, _)).WillOnce(Return(false));
384 EXPECT_CALL(tlsSystem_mock, GetThreadSpecificData()).Times(0);
385 EXPECT_CALL(tlsSystem_mock, SetThreadSpecificData(_)).Times(0);
386 EXPECT_CALL(tlsSystem_mock, TearDownForTesting()).Times(0);
387
388 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
389 };
390
391 EXPECT_DEATH(f(), "");
392 }
393
TEST_F(BaseThreadLocalStorageDeathTest,VerifyDeathIfStoringTLSDataFails)394 TEST_F(BaseThreadLocalStorageDeathTest, VerifyDeathIfStoringTLSDataFails) {
395 auto f = [] {
396 AllocatorMock allocator_mock;
397 TLSSystemMock tlsSystem_mock;
398
399 // Setup all expectations here. If we're setting them up in the parent
400 // process, they will fail because the parent doesn't execute any test.
401 EXPECT_CALL(tlsSystem_mock, SetThreadSpecificData(_))
402 .Times(1)
403 .WillOnce(Return(false));
404 EXPECT_CALL(tlsSystem_mock, TearDownForTesting()).Times(0);
405
406 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock)
407 .GetThreadLocalData();
408 };
409
410 EXPECT_DEATH(f(), "");
411 }
412
TEST_F(BaseThreadLocalStorageDeathTest,VerifyDeathIfTLSTeardownFails)413 TEST_F(BaseThreadLocalStorageDeathTest, VerifyDeathIfTLSTeardownFails) {
414 auto f = [] {
415 AllocatorMock allocator_mock;
416 TLSSystemMock tlsSystem_mock;
417
418 // Setup all expectations here. If we're setting them up in the parent
419 // process, they will fail because the parent doesn't execute any test.
420 EXPECT_CALL(tlsSystem_mock, Setup(_, _)).WillOnce(Return(true));
421 EXPECT_CALL(tlsSystem_mock, TearDownForTesting()).WillOnce(Return(false));
422
423 CreateThreadLocalStorage<DataToStore>(allocator_mock, tlsSystem_mock);
424 };
425
426 EXPECT_DEATH(f(), "");
427 }
428 #endif // GTEST_HAS_DEATH_TEST
429
430 struct BasePThreadTLSSystemTest : public ::testing::Test {
SetUpbase::allocator::dispatcher::BasePThreadTLSSystemTest431 void SetUp() override { thread_termination_counter = 0; }
432
433 protected:
ThreadTerminationFunctionbase::allocator::dispatcher::BasePThreadTLSSystemTest434 static void ThreadTerminationFunction(void*) { ++thread_termination_counter; }
435
436 static std::atomic<size_t> thread_termination_counter;
437 };
438
439 std::atomic<size_t> BasePThreadTLSSystemTest::thread_termination_counter{0};
440
TEST_F(BasePThreadTLSSystemTest,VerifySetupNTeardownSequence)441 TEST_F(BasePThreadTLSSystemTest, VerifySetupNTeardownSequence) {
442 internal::PThreadTLSSystem sut;
443
444 const std::vector<std::string> instance_ids = {"first", "second"};
445 const std::vector<std::string> crash_key_values = {"tls_system-first",
446 "tls_system-second"};
447 std::list<base::debug::CrashKeyString> crash_keys;
448
449 const auto handle_allocate =
450 [&](const char* name,
451 base::debug::CrashKeySize size) -> base::debug::CrashKeyString* {
452 const auto it_crash_key_value = std::find(std::begin(crash_key_values),
453 std::end(crash_key_values), name);
454 EXPECT_NE(it_crash_key_value, std::end(crash_key_values));
455 crash_keys.emplace_back(it_crash_key_value->c_str(), size);
456 return &(crash_keys.back());
457 };
458
459 const auto handle_set = [&](base::debug::CrashKeyString* crash_key,
460 std::string_view value) {
461 const auto it_crash_key =
462 std::find_if(std::begin(crash_keys), std::end(crash_keys),
463 [&](const base::debug::CrashKeyString& key) {
464 return &key == crash_key;
465 });
466 ASSERT_NE(it_crash_key, std::end(crash_keys));
467 ASSERT_GT(value.size(), 0ul);
468 };
469
470 const auto handle_clear = [&](base::debug::CrashKeyString* crash_key) {
471 const auto it_crash_key =
472 std::find_if(std::begin(crash_keys), std::end(crash_keys),
473 [&](const base::debug::CrashKeyString& key) {
474 return &key == crash_key;
475 });
476 ASSERT_NE(it_crash_key, std::end(crash_keys));
477
478 crash_keys.erase(it_crash_key);
479 };
480
481 auto crash_key_implementation =
482 std::make_unique<CrashKeyImplementationMock>();
483
484 InSequence execution_sequence;
485
486 for (size_t instance_index = 0; instance_index < instance_ids.size();
487 ++instance_index) {
488 EXPECT_CALL(*crash_key_implementation, Allocate(_, _))
489 .WillOnce(handle_allocate);
490 EXPECT_CALL(*crash_key_implementation, Set(_, _)).WillOnce(handle_set);
491 EXPECT_CALL(*crash_key_implementation, Clear(_)).WillOnce(handle_clear);
492 }
493
494 base::debug::SetCrashKeyImplementation(std::move(crash_key_implementation));
495
496 for (const auto& instance_id : instance_ids) {
497 ASSERT_TRUE(sut.Setup(nullptr, instance_id));
498 ASSERT_TRUE(sut.TearDownForTesting());
499 }
500
501 // Set an empty crash key impl to ensure deletion and evaluation of the mock.
502 base::debug::SetCrashKeyImplementation({});
503 }
504
TEST_F(BasePThreadTLSSystemTest,VerifyThreadTerminationFunctionIsCalled)505 TEST_F(BasePThreadTLSSystemTest, VerifyThreadTerminationFunctionIsCalled) {
506 std::array<std::thread, 10> threads;
507
508 internal::PThreadTLSSystem sut;
509 sut.Setup(&ThreadTerminationFunction, "PThreadTLSSystemInstance");
510
511 for (auto& t : threads) {
512 t = std::thread{[&] {
513 int x = 0;
514 ASSERT_TRUE(sut.SetThreadSpecificData(&x));
515 }};
516 }
517
518 for (auto& t : threads) {
519 t.join();
520 }
521
522 sut.TearDownForTesting();
523
524 EXPECT_EQ(threads.size(), thread_termination_counter);
525 }
526
TEST_F(BasePThreadTLSSystemTest,VerifyGetWithoutSetReturnsNull)527 TEST_F(BasePThreadTLSSystemTest, VerifyGetWithoutSetReturnsNull) {
528 internal::PThreadTLSSystem sut;
529 sut.Setup(nullptr, "PThreadTLSSystemInstance");
530
531 EXPECT_EQ(nullptr, sut.GetThreadSpecificData());
532
533 sut.TearDownForTesting();
534 }
535
TEST_F(BasePThreadTLSSystemTest,VerifyGetAfterTeardownReturnsNull)536 TEST_F(BasePThreadTLSSystemTest, VerifyGetAfterTeardownReturnsNull) {
537 internal::PThreadTLSSystem sut;
538 sut.Setup(nullptr, "PThreadTLSSystemInstance");
539 sut.SetThreadSpecificData(this);
540 sut.TearDownForTesting();
541
542 EXPECT_EQ(sut.GetThreadSpecificData(), nullptr);
543 }
544
TEST_F(BasePThreadTLSSystemTest,VerifyGetAfterTeardownReturnsNullThreaded)545 TEST_F(BasePThreadTLSSystemTest, VerifyGetAfterTeardownReturnsNullThreaded) {
546 std::array<std::thread, 50> threads;
547
548 std::mutex thread_worker_mutex;
549 std::condition_variable thread_counter_cv;
550 std::atomic_uint32_t thread_counter{0};
551
552 std::mutex threads_can_finish_mutex;
553 std::condition_variable threads_can_finish_cv;
554 std::atomic_bool threads_can_finish{false};
555
556 internal::PThreadTLSSystem sut;
557 ASSERT_TRUE(sut.Setup(nullptr, "PThreadTLSSystemInstance"));
558
559 for (auto& t : threads) {
560 t = std::thread{[&] {
561 // Set some thread specific data. At this stage retrieving the data must
562 // return the pointer that was originally set.
563 int x = 0;
564 ASSERT_TRUE(sut.SetThreadSpecificData(&x));
565 ASSERT_EQ(sut.GetThreadSpecificData(), &x);
566
567 // Notify the main thread that one more test thread has started.
568 {
569 std::lock_guard<std::mutex> lock(thread_worker_mutex);
570 ++thread_counter;
571 thread_counter_cv.notify_one();
572 }
573
574 // Wait for the main thread to notify about teardown of the sut.
575 {
576 std::unique_lock<std::mutex> lock(threads_can_finish_mutex);
577 threads_can_finish_cv.wait(lock,
578 [&] { return threads_can_finish.load(); });
579 }
580
581 // After teardown, thread local data must be nullptr for all threads.
582 EXPECT_EQ(sut.GetThreadSpecificData(), nullptr);
583 }};
584 }
585
586 // Wait for notification from threads that they started and passed the initial
587 // check.
588 {
589 std::unique_lock<std::mutex> lock(thread_worker_mutex);
590 thread_counter_cv.wait(
591 lock, [&] { return thread_counter.load() == threads.size(); });
592 }
593
594 ASSERT_TRUE(sut.TearDownForTesting());
595
596 // Notify all threads that the subject under test was torn down and they can
597 // proceed.
598 {
599 std::unique_lock<std::mutex> lock(threads_can_finish_mutex);
600 threads_can_finish = true;
601 threads_can_finish_cv.notify_all();
602 }
603
604 for (auto& t : threads) {
605 t.join();
606 }
607 }
608
TEST_F(BasePThreadTLSSystemTest,VerifyGetSetSequence)609 TEST_F(BasePThreadTLSSystemTest, VerifyGetSetSequence) {
610 std::array<std::thread, 50> threads;
611
612 internal::PThreadTLSSystem sut;
613 sut.Setup(nullptr, "PThreadTLSSystemInstance");
614
615 for (auto& t : threads) {
616 t = std::thread{[&] {
617 int x = 0;
618 EXPECT_TRUE(sut.SetThreadSpecificData(&x));
619 EXPECT_EQ(&x, sut.GetThreadSpecificData());
620 }};
621 }
622
623 for (auto& t : threads) {
624 t.join();
625 }
626
627 sut.TearDownForTesting();
628 }
629
630 #if DCHECK_IS_ON()
TEST_F(BasePThreadTLSSystemTest,VerifyGetWithoutSetupReturnsNull)631 TEST_F(BasePThreadTLSSystemTest, VerifyGetWithoutSetupReturnsNull) {
632 internal::PThreadTLSSystem sut;
633
634 EXPECT_EQ(sut.GetThreadSpecificData(), nullptr);
635 }
636
TEST_F(BasePThreadTLSSystemTest,VerifyStoreWithoutSetupFails)637 TEST_F(BasePThreadTLSSystemTest, VerifyStoreWithoutSetupFails) {
638 internal::PThreadTLSSystem sut;
639
640 EXPECT_FALSE(sut.SetThreadSpecificData(this));
641 }
642 #endif
643
644 #if defined(GTEST_HAS_DEATH_TEST) && DCHECK_IS_ON()
645 struct BasePThreadTLSSystemDeathTest : public ::testing::Test {};
646
TEST_F(BasePThreadTLSSystemDeathTest,VerifyDeathIfSetupTwice)647 TEST_F(BasePThreadTLSSystemDeathTest, VerifyDeathIfSetupTwice) {
648 internal::PThreadTLSSystem sut;
649
650 EXPECT_TRUE(sut.Setup(nullptr, "PThreadTLSSystemInstance"));
651 EXPECT_DEATH(sut.Setup(nullptr, "PThreadTLSSystemInstance"), "");
652 }
653
TEST_F(BasePThreadTLSSystemDeathTest,VerifyDeathIfTearDownWithoutSetup)654 TEST_F(BasePThreadTLSSystemDeathTest, VerifyDeathIfTearDownWithoutSetup) {
655 internal::PThreadTLSSystem sut;
656
657 EXPECT_DEATH(sut.TearDownForTesting(), "");
658 }
659 #endif
660 } // namespace base::allocator::dispatcher
661
662 #endif // USE_LOCAL_TLS_EMULATION()
663