xref: /aosp_15_r20/external/cronet/base/allocator/dispatcher/tls_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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