xref: /aosp_15_r20/external/cronet/base/threading/thread_local_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2012 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/threading/thread_local.h"
6 
7 #include <optional>
8 
9 #include "base/check_op.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/test/bind.h"
13 #include "base/test/gtest_util.h"
14 #include "base/threading/simple_thread.h"
15 #include "base/threading/thread.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace base {
19 
20 namespace {
21 
22 // A simple helper which sets the given boolean to true on destruction.
23 class SetTrueOnDestruction {
24  public:
SetTrueOnDestruction(bool * was_destroyed)25   explicit SetTrueOnDestruction(bool* was_destroyed)
26       : was_destroyed_(was_destroyed) {
27     CHECK_NE(was_destroyed, nullptr);
28   }
29 
30   SetTrueOnDestruction(const SetTrueOnDestruction&) = delete;
31   SetTrueOnDestruction& operator=(const SetTrueOnDestruction&) = delete;
32 
~SetTrueOnDestruction()33   ~SetTrueOnDestruction() {
34     EXPECT_FALSE(*was_destroyed_);
35     *was_destroyed_ = true;
36   }
37 
38  private:
39   const raw_ptr<bool> was_destroyed_;
40 };
41 
42 }  // namespace
43 
TEST(ThreadLocalTest,ThreadLocalOwnedPointerBasic)44 TEST(ThreadLocalTest, ThreadLocalOwnedPointerBasic) {
45   ThreadLocalOwnedPointer<SetTrueOnDestruction> tls_owned_pointer;
46   EXPECT_FALSE(tls_owned_pointer.Get());
47 
48   bool was_destroyed1 = false;
49   tls_owned_pointer.Set(
50       std::make_unique<SetTrueOnDestruction>(&was_destroyed1));
51   EXPECT_FALSE(was_destroyed1);
52   EXPECT_TRUE(tls_owned_pointer.Get());
53 
54   bool was_destroyed2 = false;
55   tls_owned_pointer.Set(
56       std::make_unique<SetTrueOnDestruction>(&was_destroyed2));
57   EXPECT_TRUE(was_destroyed1);
58   EXPECT_FALSE(was_destroyed2);
59   EXPECT_TRUE(tls_owned_pointer.Get());
60 
61   tls_owned_pointer.Set(nullptr);
62   EXPECT_TRUE(was_destroyed1);
63   EXPECT_TRUE(was_destroyed2);
64   EXPECT_FALSE(tls_owned_pointer.Get());
65 }
66 
TEST(ThreadLocalTest,ThreadLocalOwnedPointerFreedOnThreadExit)67 TEST(ThreadLocalTest, ThreadLocalOwnedPointerFreedOnThreadExit) {
68   bool tls_was_destroyed = false;
69   ThreadLocalOwnedPointer<SetTrueOnDestruction> tls_owned_pointer;
70 
71   Thread thread("TestThread");
72   thread.Start();
73 
74   WaitableEvent tls_set;
75 
76   thread.task_runner()->PostTask(
77       FROM_HERE, BindLambdaForTesting([&]() {
78         tls_owned_pointer.Set(
79             std::make_unique<SetTrueOnDestruction>(&tls_was_destroyed));
80         tls_set.Signal();
81       }));
82 
83   tls_set.Wait();
84   EXPECT_FALSE(tls_was_destroyed);
85 
86   thread.Stop();
87   EXPECT_TRUE(tls_was_destroyed);
88 }
89 
TEST(ThreadLocalTest,ThreadLocalOwnedPointerCleansUpMainThreadOnDestruction)90 TEST(ThreadLocalTest, ThreadLocalOwnedPointerCleansUpMainThreadOnDestruction) {
91   std::optional<ThreadLocalOwnedPointer<SetTrueOnDestruction>>
92       tls_owned_pointer(std::in_place);
93   bool tls_was_destroyed_other = false;
94 
95   Thread thread("TestThread");
96   thread.Start();
97 
98   WaitableEvent tls_set;
99 
100   thread.task_runner()->PostTask(
101       FROM_HERE, BindLambdaForTesting([&]() {
102         tls_owned_pointer->Set(
103             std::make_unique<SetTrueOnDestruction>(&tls_was_destroyed_other));
104         tls_set.Signal();
105       }));
106 
107   tls_set.Wait();
108 
109   bool tls_was_destroyed_main = false;
110   tls_owned_pointer->Set(
111       std::make_unique<SetTrueOnDestruction>(&tls_was_destroyed_main));
112   EXPECT_FALSE(tls_was_destroyed_other);
113   EXPECT_FALSE(tls_was_destroyed_main);
114 
115   // Stopping the thread relinquishes its TLS (as in
116   // ThreadLocalOwnedPointerFreedOnThreadExit).
117   thread.Stop();
118   EXPECT_TRUE(tls_was_destroyed_other);
119   EXPECT_FALSE(tls_was_destroyed_main);
120 
121   // Deleting the ThreadLocalOwnedPointer instance on the main thread is allowed
122   // iff that's the only thread with remaining storage (ref. disallowed use case
123   // in ThreadLocalOwnedPointerDeathIfDestroyedWithActiveThread below). In that
124   // case, the storage on the main thread is freed before releasing the TLS
125   // slot.
126   tls_owned_pointer.reset();
127   EXPECT_TRUE(tls_was_destroyed_main);
128 }
129 
TEST(ThreadLocalTest,ThreadLocalOwnedPointerDeathIfDestroyedWithActiveThread)130 TEST(ThreadLocalTest, ThreadLocalOwnedPointerDeathIfDestroyedWithActiveThread) {
131   GTEST_FLAG_SET(death_test_style, "threadsafe");
132 
133   std::optional<ThreadLocalOwnedPointer<int>> tls_owned_pointer(std::in_place);
134 
135   Thread thread("TestThread");
136   thread.Start();
137 
138   WaitableEvent tls_set;
139 
140   thread.task_runner()->PostTask(
141       FROM_HERE, BindLambdaForTesting([&]() {
142         tls_owned_pointer->Set(std::make_unique<int>(1));
143         tls_set.Signal();
144       }));
145 
146   tls_set.Wait();
147 
148   EXPECT_DCHECK_DEATH({ tls_owned_pointer.reset(); });
149 }
150 
TEST(ThreadLocalTest,ThreadLocalOwnedPointerMultiThreadedAndStaticStorage)151 TEST(ThreadLocalTest, ThreadLocalOwnedPointerMultiThreadedAndStaticStorage) {
152   constexpr int kNumThreads = 16;
153 
154   static ThreadLocalOwnedPointer<SetTrueOnDestruction> tls_owned_pointer;
155 
156   std::array<bool, kNumThreads> were_destroyed{};
157 
158   std::array<std::unique_ptr<Thread>, kNumThreads> threads;
159 
160   for (auto& thread : threads) {
161     thread = std::make_unique<Thread>("TestThread");
162     thread->Start();
163   }
164 
165   for (const auto& thread : threads) {
166     // Waiting is unnecessary but enhances the likelihood of data races in the
167     // next steps.
168     thread->WaitUntilThreadStarted();
169   }
170 
171   for (const bool was_destroyed : were_destroyed) {
172     EXPECT_FALSE(was_destroyed);
173   }
174 
175   for (int i = 0; i < kNumThreads; ++i) {
176     threads[i]->task_runner()->PostTask(
177         FROM_HERE,
178         BindOnce(
179             [](bool* was_destroyed) {
180               tls_owned_pointer.Set(
181                   std::make_unique<SetTrueOnDestruction>(was_destroyed));
182             },
183             &were_destroyed[i]));
184   }
185 
186   static bool main_thread_was_destroyed = false;
187   // Even when the test is run multiple times in the same process: TLS should
188   // never be destroyed until static uninitialization.
189   EXPECT_FALSE(main_thread_was_destroyed);
190 
191   tls_owned_pointer.Set(
192       std::make_unique<SetTrueOnDestruction>(&main_thread_was_destroyed));
193 
194   for (const auto& thread : threads) {
195     thread->Stop();
196   }
197 
198   for (const bool was_destroyed : were_destroyed) {
199     EXPECT_TRUE(was_destroyed);
200   }
201 
202   // The main thread's TLS still wasn't destroyed (let the test unfold naturally
203   // through static uninitialization).
204   EXPECT_FALSE(main_thread_was_destroyed);
205 }
206 
207 }  // namespace base
208