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 thread makes it possible |
| 200 // 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))); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 EXPECT_FALSE(a.IsRunning()); | 280 EXPECT_FALSE(a.IsRunning()); |
225 | 281 |
226 EXPECT_TRUE(a.Start()); | 282 EXPECT_TRUE(a.Start()); |
227 EXPECT_TRUE(a.message_loop()); | 283 EXPECT_TRUE(a.message_loop()); |
228 EXPECT_TRUE(a.IsRunning()); | 284 EXPECT_TRUE(a.IsRunning()); |
229 a.Stop(); | 285 a.Stop(); |
230 EXPECT_FALSE(a.message_loop()); | 286 EXPECT_FALSE(a.message_loop()); |
231 EXPECT_FALSE(a.IsRunning()); | 287 EXPECT_FALSE(a.IsRunning()); |
232 } | 288 } |
233 | 289 |
| 290 TEST_F(ThreadTest, StartTwiceNonJoinableNotAllowed) { |
| 291 Thread a("StartTwiceNonJoinable"); |
| 292 |
| 293 Thread::Options options; |
| 294 options.joinable = false; |
| 295 EXPECT_TRUE(a.StartWithOptions(options)); |
| 296 EXPECT_TRUE(a.message_loop()); |
| 297 EXPECT_TRUE(a.IsRunning()); |
| 298 |
| 299 // Signaled when last task on |a| is processed. |
| 300 base::WaitableEvent last_task_event( |
| 301 base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 302 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 303 a.task_runner()->PostTask(FROM_HERE, |
| 304 base::Bind(&base::WaitableEvent::Signal, |
| 305 base::Unretained(&last_task_event))); |
| 306 |
| 307 // Stop() is non-blocking, but Yield() to |a|, wait for last task to be |
| 308 // processed and a little more for QuitWhenIdle() to unwind before considering |
| 309 // the thread "stopped". |
| 310 a.Stop(); |
| 311 base::PlatformThread::YieldCurrentThread(); |
| 312 last_task_event.Wait(); |
| 313 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 314 |
| 315 // This test assumes that the above was sufficient to let the thread fully |
| 316 // stop. |
| 317 ASSERT_FALSE(a.IsRunning()); |
| 318 |
| 319 // Restarting it should not be allowed. |
| 320 EXPECT_DCHECK_DEATH(a.Start(), ""); |
| 321 } |
| 322 |
234 TEST_F(ThreadTest, ThreadName) { | 323 TEST_F(ThreadTest, ThreadName) { |
235 Thread a("ThreadName"); | 324 Thread a("ThreadName"); |
236 EXPECT_TRUE(a.Start()); | 325 EXPECT_TRUE(a.Start()); |
237 EXPECT_EQ("ThreadName", a.thread_name()); | 326 EXPECT_EQ("ThreadName", a.thread_name()); |
238 } | 327 } |
239 | 328 |
240 TEST_F(ThreadTest, ThreadId) { | 329 TEST_F(ThreadTest, ThreadId) { |
241 Thread a("ThreadId0"); | 330 Thread a("ThreadId0"); |
242 Thread b("ThreadId1"); | 331 Thread b("ThreadId1"); |
243 a.Start(); | 332 a.Start(); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 EXPECT_FALSE(a.task_runner()); | 414 EXPECT_FALSE(a.task_runner()); |
326 } | 415 } |
327 | 416 |
328 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { | 417 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { |
329 Thread a("MultipleWaitUntilThreadStarted"); | 418 Thread a("MultipleWaitUntilThreadStarted"); |
330 EXPECT_TRUE(a.Start()); | 419 EXPECT_TRUE(a.Start()); |
331 // It's OK to call WaitUntilThreadStarted() multiple times. | 420 // It's OK to call WaitUntilThreadStarted() multiple times. |
332 EXPECT_TRUE(a.WaitUntilThreadStarted()); | 421 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
333 EXPECT_TRUE(a.WaitUntilThreadStarted()); | 422 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
334 } | 423 } |
| 424 |
| 425 namespace { |
| 426 |
| 427 // A Thread which uses a MessageLoop on the stack. It won't start a real |
| 428 // underlying thread (instead its messages can be processed by a RunLoop on the |
| 429 // stack). |
| 430 class ExternalMessageLoopThread : public Thread { |
| 431 public: |
| 432 ExternalMessageLoopThread() : Thread("ExternalMessageLoopThread") {} |
| 433 |
| 434 ~ExternalMessageLoopThread() override { Stop(); } |
| 435 |
| 436 void InstallMessageLoop() { SetMessageLoop(&external_message_loop_); } |
| 437 |
| 438 private: |
| 439 base::MessageLoop external_message_loop_; |
| 440 |
| 441 DISALLOW_COPY_AND_ASSIGN(ExternalMessageLoopThread); |
| 442 }; |
| 443 |
| 444 } // namespace |
| 445 |
| 446 TEST_F(ThreadTest, ExternalMessageLoop) { |
| 447 ExternalMessageLoopThread a; |
| 448 EXPECT_FALSE(a.message_loop()); |
| 449 EXPECT_FALSE(a.IsRunning()); |
| 450 |
| 451 a.InstallMessageLoop(); |
| 452 EXPECT_TRUE(a.message_loop()); |
| 453 EXPECT_TRUE(a.IsRunning()); |
| 454 |
| 455 bool ran = false; |
| 456 a.task_runner()->PostTask( |
| 457 FROM_HERE, base::Bind([](bool* toggled) { *toggled = true; }, &ran)); |
| 458 base::RunLoop().RunUntilIdle(); |
| 459 EXPECT_TRUE(ran); |
| 460 |
| 461 a.Stop(); |
| 462 EXPECT_FALSE(a.message_loop()); |
| 463 EXPECT_FALSE(a.IsRunning()); |
| 464 |
| 465 // Confirm that running any remaining tasks posted from Stop() goes smoothly |
| 466 // (e.g. https://codereview.chromium.org/2135413003/#ps300001 crashed if |
| 467 // StopSoon() posted Thread::ThreadQuitHelper() while |run_loop_| was null). |
| 468 base::RunLoop().RunUntilIdle(); |
| 469 } |
OLD | NEW |