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