OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/threading/thread.h" | 5 #include "base/threading/thread.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/location.h" | 12 #include "base/macros.h" |
| 13 #include "base/message_loop/message_loop.h" |
| 14 #include "base/run_loop.h" |
13 #include "base/single_thread_task_runner.h" | 15 #include "base/single_thread_task_runner.h" |
14 #include "base/synchronization/waitable_event.h" | 16 #include "base/synchronization/waitable_event.h" |
15 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 17 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| 18 #include "base/threading/platform_thread.h" |
16 #include "build/build_config.h" | 19 #include "build/build_config.h" |
17 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
18 #include "testing/platform_test.h" | 21 #include "testing/platform_test.h" |
19 | 22 |
| 23 // Death tests misbehave on Android. |
| 24 // TODO(gab): Remove this when https://codereview.chromium.org/2162053006 |
| 25 // lands. |
| 26 #if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) |
| 27 #define EXPECT_DCHECK_DEATH(statement, regex) EXPECT_DEATH(statement, regex) |
| 28 #else |
| 29 #define EXPECT_DCHECK_DEATH(statement, regex) |
| 30 #endif |
| 31 |
20 using base::Thread; | 32 using base::Thread; |
21 | 33 |
22 typedef PlatformTest ThreadTest; | 34 typedef PlatformTest ThreadTest; |
23 | 35 |
24 namespace { | 36 namespace { |
25 | 37 |
26 void ToggleValue(bool* value) { | 38 void ToggleValue(bool* value) { |
27 ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean " | 39 ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean " |
28 "in base/thread_unittest"); | 40 "in base/thread_unittest"); |
29 *value = !*value; | 41 *value = !*value; |
30 } | 42 } |
31 | 43 |
32 class SleepInsideInitThread : public Thread { | 44 class SleepInsideInitThread : public Thread { |
33 public: | 45 public: |
34 SleepInsideInitThread() : Thread("none") { | 46 SleepInsideInitThread() : Thread("none") { |
35 init_called_ = false; | 47 init_called_ = false; |
36 ANNOTATE_BENIGN_RACE( | 48 ANNOTATE_BENIGN_RACE( |
37 this, "Benign test-only data race on vptr - http://crbug.com/98219"); | 49 this, "Benign test-only data race on vptr - http://crbug.com/98219"); |
38 } | 50 } |
39 ~SleepInsideInitThread() override { Stop(); } | 51 ~SleepInsideInitThread() override { Stop(); } |
40 | 52 |
41 void Init() override { | 53 void Init() override { |
42 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); | 54 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); |
43 init_called_ = true; | 55 init_called_ = true; |
44 } | 56 } |
45 bool InitCalled() { return init_called_; } | 57 bool InitCalled() { return init_called_; } |
| 58 |
46 private: | 59 private: |
47 bool init_called_; | 60 bool init_called_; |
| 61 |
| 62 DISALLOW_COPY_AND_ASSIGN(SleepInsideInitThread); |
48 }; | 63 }; |
49 | 64 |
50 enum ThreadEvent { | 65 enum ThreadEvent { |
51 // Thread::Init() was called. | 66 // Thread::Init() was called. |
52 THREAD_EVENT_INIT = 0, | 67 THREAD_EVENT_INIT = 0, |
53 | 68 |
54 // The MessageLoop for the thread was deleted. | 69 // The MessageLoop for the thread was deleted. |
55 THREAD_EVENT_MESSAGE_LOOP_DESTROYED, | 70 THREAD_EVENT_MESSAGE_LOOP_DESTROYED, |
56 | 71 |
57 // Thread::CleanUp() was called. | 72 // Thread::CleanUp() was called. |
(...skipping 16 matching lines...) Expand all Loading... |
74 } | 89 } |
75 | 90 |
76 ~CaptureToEventList() override { Stop(); } | 91 ~CaptureToEventList() override { Stop(); } |
77 | 92 |
78 void Init() override { event_list_->push_back(THREAD_EVENT_INIT); } | 93 void Init() override { event_list_->push_back(THREAD_EVENT_INIT); } |
79 | 94 |
80 void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); } | 95 void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); } |
81 | 96 |
82 private: | 97 private: |
83 EventList* event_list_; | 98 EventList* event_list_; |
| 99 |
| 100 DISALLOW_COPY_AND_ASSIGN(CaptureToEventList); |
84 }; | 101 }; |
85 | 102 |
86 // Observer that writes a value into |event_list| when a message loop has been | 103 // Observer that writes a value into |event_list| when a message loop has been |
87 // destroyed. | 104 // destroyed. |
88 class CapturingDestructionObserver | 105 class CapturingDestructionObserver |
89 : public base::MessageLoop::DestructionObserver { | 106 : public base::MessageLoop::DestructionObserver { |
90 public: | 107 public: |
91 // |event_list| must remain valid throughout the observer's lifetime. | 108 // |event_list| must remain valid throughout the observer's lifetime. |
92 explicit CapturingDestructionObserver(EventList* event_list) | 109 explicit CapturingDestructionObserver(EventList* event_list) |
93 : event_list_(event_list) { | 110 : event_list_(event_list) { |
94 } | 111 } |
95 | 112 |
96 // DestructionObserver implementation: | 113 // DestructionObserver implementation: |
97 void WillDestroyCurrentMessageLoop() override { | 114 void WillDestroyCurrentMessageLoop() override { |
98 event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED); | 115 event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED); |
99 event_list_ = NULL; | 116 event_list_ = NULL; |
100 } | 117 } |
101 | 118 |
102 private: | 119 private: |
103 EventList* event_list_; | 120 EventList* event_list_; |
| 121 |
| 122 DISALLOW_COPY_AND_ASSIGN(CapturingDestructionObserver); |
104 }; | 123 }; |
105 | 124 |
106 // Task that adds a destruction observer to the current message loop. | 125 // Task that adds a destruction observer to the current message loop. |
107 void RegisterDestructionObserver( | 126 void RegisterDestructionObserver( |
108 base::MessageLoop::DestructionObserver* observer) { | 127 base::MessageLoop::DestructionObserver* observer) { |
109 base::MessageLoop::current()->AddDestructionObserver(observer); | 128 base::MessageLoop::current()->AddDestructionObserver(observer); |
110 } | 129 } |
111 | 130 |
112 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then | 131 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then |
113 // signal |event|. | 132 // signal |event|. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 EXPECT_TRUE(a.message_loop()); | 176 EXPECT_TRUE(a.message_loop()); |
158 EXPECT_TRUE(a.IsRunning()); | 177 EXPECT_TRUE(a.IsRunning()); |
159 | 178 |
160 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 179 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
161 base::WaitableEvent::InitialState::NOT_SIGNALED); | 180 base::WaitableEvent::InitialState::NOT_SIGNALED); |
162 a.task_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal, | 181 a.task_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal, |
163 base::Unretained(&event))); | 182 base::Unretained(&event))); |
164 event.Wait(); | 183 event.Wait(); |
165 } | 184 } |
166 | 185 |
167 TEST_F(ThreadTest, TwoTasks) { | 186 TEST_F(ThreadTest, StartWithOptions_NonJoinable) { |
| 187 Thread a("StartNonJoinable"); |
| 188 Thread::Options options; |
| 189 options.joinable = false; |
| 190 EXPECT_TRUE(a.StartWithOptions(options)); |
| 191 EXPECT_TRUE(a.message_loop()); |
| 192 EXPECT_TRUE(a.IsRunning()); |
| 193 |
| 194 // Without this call this test is racy. The above IsRunning() succeeds because |
| 195 // of an early-return condition while between Start() and Stop(), after |
| 196 // invoking Stop() below this early-return condition is no longer satisfied |
| 197 // and the real |is_running_| bit has to be checked. It could still be false |
| 198 // if the message loop hasn't started for real in practice. This is only a |
| 199 // requirement for this test because the non-joinable property makes it |
| 200 // possible to return from Stop() before the thread has even started. |
| 201 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 202 |
| 203 // Make the thread block until |block_event| is signaled. |
| 204 base::WaitableEvent block_event( |
| 205 base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 206 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 207 a.task_runner()->PostTask( |
| 208 FROM_HERE, |
| 209 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&block_event))); |
| 210 |
| 211 // Stop() shouldn't block despite the thread still being alive. |
| 212 a.Stop(); |
| 213 EXPECT_TRUE(a.IsRunning()); |
| 214 |
| 215 // Unblock the task and give a bit of extra time to unwind QuitWhenIdle(). |
| 216 block_event.Signal(); |
| 217 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 218 |
| 219 // The thread should now have stopped on its own. |
| 220 EXPECT_FALSE(a.IsRunning()); |
| 221 } |
| 222 |
| 223 TEST_F(ThreadTest, TwoTasksOnJoinableThread) { |
168 bool was_invoked = false; | 224 bool was_invoked = false; |
169 { | 225 { |
170 Thread a("TwoTasks"); | 226 Thread a("TwoTasksOnJoinableThread"); |
171 EXPECT_TRUE(a.Start()); | 227 EXPECT_TRUE(a.Start()); |
172 EXPECT_TRUE(a.message_loop()); | 228 EXPECT_TRUE(a.message_loop()); |
173 | 229 |
174 // Test that all events are dispatched before the Thread object is | 230 // Test that all events are dispatched before the Thread object is |
175 // destroyed. We do this by dispatching a sleep event before the | 231 // destroyed. We do this by dispatching a sleep event before the |
176 // event that will toggle our sentinel value. | 232 // event that will toggle our sentinel value. |
177 a.task_runner()->PostTask( | 233 a.task_runner()->PostTask( |
178 FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>( | 234 FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>( |
179 &base::PlatformThread::Sleep), | 235 &base::PlatformThread::Sleep), |
180 base::TimeDelta::FromMilliseconds(20))); | 236 base::TimeDelta::FromMilliseconds(20))); |
181 a.task_runner()->PostTask(FROM_HERE, | 237 a.task_runner()->PostTask(FROM_HERE, |
182 base::Bind(&ToggleValue, &was_invoked)); | 238 base::Bind(&ToggleValue, &was_invoked)); |
183 } | 239 } |
184 EXPECT_TRUE(was_invoked); | 240 EXPECT_TRUE(was_invoked); |
185 } | 241 } |
186 | 242 |
| 243 TEST_F(ThreadTest, DestroyWhileRunningIsSafe) { |
| 244 Thread a("DestroyWhileRunningIsSafe"); |
| 245 EXPECT_TRUE(a.Start()); |
| 246 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 247 } |
| 248 |
| 249 // TODO(gab): Enable this test when destroying a non-joinable Thread instance |
| 250 // is supported (proposal @ https://crbug.com/629139#c14). |
| 251 // TEST_F(ThreadTest, DestroyWhileRunningNonJoinableIsSafe) { |
| 252 // { |
| 253 // Thread a("DestroyWhileRunningNonJoinableIsSafe"); |
| 254 // Thread::Options options; |
| 255 // options.joinable = false; |
| 256 // EXPECT_TRUE(a.StartWithOptions(options)); |
| 257 // EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 258 // } |
| 259 // |
| 260 // // Attempt to catch use-after-frees from the non-joinable thread in the |
| 261 // // scope of this test if any. |
| 262 // base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 263 // } |
| 264 |
187 TEST_F(ThreadTest, StopSoon) { | 265 TEST_F(ThreadTest, StopSoon) { |
188 Thread a("StopSoon"); | 266 Thread a("StopSoon"); |
189 EXPECT_TRUE(a.Start()); | 267 EXPECT_TRUE(a.Start()); |
190 EXPECT_TRUE(a.message_loop()); | 268 EXPECT_TRUE(a.message_loop()); |
191 EXPECT_TRUE(a.IsRunning()); | 269 EXPECT_TRUE(a.IsRunning()); |
192 a.StopSoon(); | 270 a.StopSoon(); |
193 a.Stop(); | 271 a.Stop(); |
194 EXPECT_FALSE(a.message_loop()); | 272 EXPECT_FALSE(a.message_loop()); |
195 EXPECT_FALSE(a.IsRunning()); | 273 EXPECT_FALSE(a.IsRunning()); |
196 } | 274 } |
(...skipping 27 matching lines...) Expand all Loading... |
224 EXPECT_FALSE(a.IsRunning()); | 302 EXPECT_FALSE(a.IsRunning()); |
225 | 303 |
226 EXPECT_TRUE(a.Start()); | 304 EXPECT_TRUE(a.Start()); |
227 EXPECT_TRUE(a.message_loop()); | 305 EXPECT_TRUE(a.message_loop()); |
228 EXPECT_TRUE(a.IsRunning()); | 306 EXPECT_TRUE(a.IsRunning()); |
229 a.Stop(); | 307 a.Stop(); |
230 EXPECT_FALSE(a.message_loop()); | 308 EXPECT_FALSE(a.message_loop()); |
231 EXPECT_FALSE(a.IsRunning()); | 309 EXPECT_FALSE(a.IsRunning()); |
232 } | 310 } |
233 | 311 |
| 312 TEST_F(ThreadTest, StartTwiceNonJoinableNotAllowed) { |
| 313 Thread a("StartTwiceNonJoinable"); |
| 314 |
| 315 Thread::Options options; |
| 316 options.joinable = false; |
| 317 EXPECT_TRUE(a.StartWithOptions(options)); |
| 318 EXPECT_TRUE(a.message_loop()); |
| 319 EXPECT_TRUE(a.IsRunning()); |
| 320 |
| 321 // Signaled when last task on |a| is processed. |
| 322 base::WaitableEvent last_task_event( |
| 323 base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 324 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 325 a.task_runner()->PostTask(FROM_HERE, |
| 326 base::Bind(&base::WaitableEvent::Signal, |
| 327 base::Unretained(&last_task_event))); |
| 328 |
| 329 // Stop() is non-blocking, but Yield() to |a|, wait for last task to be |
| 330 // processed and a little more for QuitWhenIdle() to unwind before considering |
| 331 // the thread "stopped". |
| 332 a.Stop(); |
| 333 base::PlatformThread::YieldCurrentThread(); |
| 334 last_task_event.Wait(); |
| 335 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 336 |
| 337 // This test assumes that the above was sufficient to let the thread fully |
| 338 // stop. |
| 339 ASSERT_FALSE(a.IsRunning()); |
| 340 |
| 341 // Restarting it should not be allowed. |
| 342 EXPECT_DCHECK_DEATH(a.Start(), ""); |
| 343 } |
| 344 |
234 TEST_F(ThreadTest, ThreadName) { | 345 TEST_F(ThreadTest, ThreadName) { |
235 Thread a("ThreadName"); | 346 Thread a("ThreadName"); |
236 EXPECT_TRUE(a.Start()); | 347 EXPECT_TRUE(a.Start()); |
237 EXPECT_EQ("ThreadName", a.thread_name()); | 348 EXPECT_EQ("ThreadName", a.thread_name()); |
238 } | 349 } |
239 | 350 |
240 TEST_F(ThreadTest, ThreadId) { | 351 TEST_F(ThreadTest, ThreadId) { |
241 Thread a("ThreadId0"); | 352 Thread a("ThreadId0"); |
242 Thread b("ThreadId1"); | 353 Thread b("ThreadId1"); |
243 a.Start(); | 354 a.Start(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 EXPECT_FALSE(a.task_runner()); | 436 EXPECT_FALSE(a.task_runner()); |
326 } | 437 } |
327 | 438 |
328 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { | 439 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { |
329 Thread a("MultipleWaitUntilThreadStarted"); | 440 Thread a("MultipleWaitUntilThreadStarted"); |
330 EXPECT_TRUE(a.Start()); | 441 EXPECT_TRUE(a.Start()); |
331 // It's OK to call WaitUntilThreadStarted() multiple times. | 442 // It's OK to call WaitUntilThreadStarted() multiple times. |
332 EXPECT_TRUE(a.WaitUntilThreadStarted()); | 443 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
333 EXPECT_TRUE(a.WaitUntilThreadStarted()); | 444 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
334 } | 445 } |
| 446 |
| 447 namespace { |
| 448 |
| 449 // A Thread which uses a MessageLoop on the stack. It won't start a real |
| 450 // underlying thread (instead its messages can be processed by a RunLoop on the |
| 451 // stack). |
| 452 class ExternalMessageLoopThread : public Thread { |
| 453 public: |
| 454 ExternalMessageLoopThread() : Thread("ExternalMessageLoopThread") {} |
| 455 |
| 456 ~ExternalMessageLoopThread() override { Stop(); } |
| 457 |
| 458 void InstallMessageLoop() { SetMessageLoop(&external_message_loop_); } |
| 459 |
| 460 private: |
| 461 base::MessageLoop external_message_loop_; |
| 462 |
| 463 DISALLOW_COPY_AND_ASSIGN(ExternalMessageLoopThread); |
| 464 }; |
| 465 |
| 466 } // namespace |
| 467 |
| 468 TEST_F(ThreadTest, ExternalMessageLoop) { |
| 469 ExternalMessageLoopThread a; |
| 470 EXPECT_FALSE(a.message_loop()); |
| 471 EXPECT_FALSE(a.IsRunning()); |
| 472 |
| 473 a.InstallMessageLoop(); |
| 474 EXPECT_TRUE(a.message_loop()); |
| 475 EXPECT_TRUE(a.IsRunning()); |
| 476 |
| 477 bool ran = false; |
| 478 a.task_runner()->PostTask( |
| 479 FROM_HERE, base::Bind([](bool* toggled) { *toggled = true; }, &ran)); |
| 480 base::RunLoop().RunUntilIdle(); |
| 481 EXPECT_TRUE(ran); |
| 482 |
| 483 a.Stop(); |
| 484 EXPECT_FALSE(a.message_loop()); |
| 485 EXPECT_FALSE(a.IsRunning()); |
| 486 |
| 487 // Confirm that running any remaining tasks posted from Stop() goes smoothly |
| 488 // (e.g. https://codereview.chromium.org/2135413003/#ps300001 crashed if |
| 489 // StopSoon() posted Thread::ThreadQuitHelper() while |run_loop_| was null). |
| 490 base::RunLoop().RunUntilIdle(); |
| 491 } |
OLD | NEW |