• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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