| 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/debug/leak_annotations.h" |
| 13 #include "base/macros.h" |
| 14 #include "base/message_loop/message_loop.h" |
| 15 #include "base/run_loop.h" |
| 13 #include "base/single_thread_task_runner.h" | 16 #include "base/single_thread_task_runner.h" |
| 14 #include "base/synchronization/waitable_event.h" | 17 #include "base/synchronization/waitable_event.h" |
| 18 #include "base/test/gtest_util.h" |
| 15 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 19 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
| 20 #include "base/threading/platform_thread.h" |
| 16 #include "build/build_config.h" | 21 #include "build/build_config.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
| 18 #include "testing/platform_test.h" | 23 #include "testing/platform_test.h" |
| 19 | 24 |
| 20 using base::Thread; | 25 using base::Thread; |
| 21 | 26 |
| 22 typedef PlatformTest ThreadTest; | 27 typedef PlatformTest ThreadTest; |
| 23 | 28 |
| 24 namespace { | 29 namespace { |
| 25 | 30 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 36 ANNOTATE_BENIGN_RACE( | 41 ANNOTATE_BENIGN_RACE( |
| 37 this, "Benign test-only data race on vptr - http://crbug.com/98219"); | 42 this, "Benign test-only data race on vptr - http://crbug.com/98219"); |
| 38 } | 43 } |
| 39 ~SleepInsideInitThread() override { Stop(); } | 44 ~SleepInsideInitThread() override { Stop(); } |
| 40 | 45 |
| 41 void Init() override { | 46 void Init() override { |
| 42 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); | 47 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500)); |
| 43 init_called_ = true; | 48 init_called_ = true; |
| 44 } | 49 } |
| 45 bool InitCalled() { return init_called_; } | 50 bool InitCalled() { return init_called_; } |
| 51 |
| 46 private: | 52 private: |
| 47 bool init_called_; | 53 bool init_called_; |
| 54 |
| 55 DISALLOW_COPY_AND_ASSIGN(SleepInsideInitThread); |
| 48 }; | 56 }; |
| 49 | 57 |
| 50 enum ThreadEvent { | 58 enum ThreadEvent { |
| 51 // Thread::Init() was called. | 59 // Thread::Init() was called. |
| 52 THREAD_EVENT_INIT = 0, | 60 THREAD_EVENT_INIT = 0, |
| 53 | 61 |
| 54 // The MessageLoop for the thread was deleted. | 62 // The MessageLoop for the thread was deleted. |
| 55 THREAD_EVENT_MESSAGE_LOOP_DESTROYED, | 63 THREAD_EVENT_MESSAGE_LOOP_DESTROYED, |
| 56 | 64 |
| 57 // Thread::CleanUp() was called. | 65 // Thread::CleanUp() was called. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 74 } | 82 } |
| 75 | 83 |
| 76 ~CaptureToEventList() override { Stop(); } | 84 ~CaptureToEventList() override { Stop(); } |
| 77 | 85 |
| 78 void Init() override { event_list_->push_back(THREAD_EVENT_INIT); } | 86 void Init() override { event_list_->push_back(THREAD_EVENT_INIT); } |
| 79 | 87 |
| 80 void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); } | 88 void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); } |
| 81 | 89 |
| 82 private: | 90 private: |
| 83 EventList* event_list_; | 91 EventList* event_list_; |
| 92 |
| 93 DISALLOW_COPY_AND_ASSIGN(CaptureToEventList); |
| 84 }; | 94 }; |
| 85 | 95 |
| 86 // Observer that writes a value into |event_list| when a message loop has been | 96 // Observer that writes a value into |event_list| when a message loop has been |
| 87 // destroyed. | 97 // destroyed. |
| 88 class CapturingDestructionObserver | 98 class CapturingDestructionObserver |
| 89 : public base::MessageLoop::DestructionObserver { | 99 : public base::MessageLoop::DestructionObserver { |
| 90 public: | 100 public: |
| 91 // |event_list| must remain valid throughout the observer's lifetime. | 101 // |event_list| must remain valid throughout the observer's lifetime. |
| 92 explicit CapturingDestructionObserver(EventList* event_list) | 102 explicit CapturingDestructionObserver(EventList* event_list) |
| 93 : event_list_(event_list) { | 103 : event_list_(event_list) { |
| 94 } | 104 } |
| 95 | 105 |
| 96 // DestructionObserver implementation: | 106 // DestructionObserver implementation: |
| 97 void WillDestroyCurrentMessageLoop() override { | 107 void WillDestroyCurrentMessageLoop() override { |
| 98 event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED); | 108 event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED); |
| 99 event_list_ = NULL; | 109 event_list_ = NULL; |
| 100 } | 110 } |
| 101 | 111 |
| 102 private: | 112 private: |
| 103 EventList* event_list_; | 113 EventList* event_list_; |
| 114 |
| 115 DISALLOW_COPY_AND_ASSIGN(CapturingDestructionObserver); |
| 104 }; | 116 }; |
| 105 | 117 |
| 106 // Task that adds a destruction observer to the current message loop. | 118 // Task that adds a destruction observer to the current message loop. |
| 107 void RegisterDestructionObserver( | 119 void RegisterDestructionObserver( |
| 108 base::MessageLoop::DestructionObserver* observer) { | 120 base::MessageLoop::DestructionObserver* observer) { |
| 109 base::MessageLoop::current()->AddDestructionObserver(observer); | 121 base::MessageLoop::current()->AddDestructionObserver(observer); |
| 110 } | 122 } |
| 111 | 123 |
| 112 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then | 124 // Task that calls GetThreadId() of |thread|, stores the result into |id|, then |
| 113 // signal |event|. | 125 // signal |event|. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 135 EXPECT_TRUE(a.message_loop()); | 147 EXPECT_TRUE(a.message_loop()); |
| 136 EXPECT_TRUE(a.IsRunning()); | 148 EXPECT_TRUE(a.IsRunning()); |
| 137 | 149 |
| 138 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, | 150 base::WaitableEvent event(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 139 base::WaitableEvent::InitialState::NOT_SIGNALED); | 151 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 140 a.task_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal, | 152 a.task_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal, |
| 141 base::Unretained(&event))); | 153 base::Unretained(&event))); |
| 142 event.Wait(); | 154 event.Wait(); |
| 143 } | 155 } |
| 144 | 156 |
| 145 TEST_F(ThreadTest, TwoTasks) { | 157 TEST_F(ThreadTest, StartWithOptions_NonJoinable) { |
| 158 Thread* a = new Thread("StartNonJoinable"); |
| 159 // Non-joinable threads have to be leaked for now (see |
| 160 // Thread::Options::joinable for details). |
| 161 ANNOTATE_LEAKING_OBJECT_PTR(a); |
| 162 |
| 163 Thread::Options options; |
| 164 options.joinable = false; |
| 165 EXPECT_TRUE(a->StartWithOptions(options)); |
| 166 EXPECT_TRUE(a->message_loop()); |
| 167 EXPECT_TRUE(a->IsRunning()); |
| 168 |
| 169 // Without this call this test is racy. The above IsRunning() succeeds because |
| 170 // of an early-return condition while between Start() and StopSoon(), after |
| 171 // invoking StopSoon() below this early-return condition is no longer |
| 172 // satisfied and the real |is_running_| bit has to be checked. It could still |
| 173 // be false if the message loop hasn't started for real in practice. This is |
| 174 // only a requirement for this test because the non-joinable property forces |
| 175 // it to use StopSoon() and not wait for a complete Stop(). |
| 176 EXPECT_TRUE(a->WaitUntilThreadStarted()); |
| 177 |
| 178 // Make the thread block until |block_event| is signaled. |
| 179 base::WaitableEvent block_event( |
| 180 base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 181 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 182 a->task_runner()->PostTask( |
| 183 FROM_HERE, |
| 184 base::Bind(&base::WaitableEvent::Wait, base::Unretained(&block_event))); |
| 185 |
| 186 a->StopSoon(); |
| 187 EXPECT_TRUE(a->IsRunning()); |
| 188 |
| 189 // Unblock the task and give a bit of extra time to unwind QuitWhenIdle(). |
| 190 block_event.Signal(); |
| 191 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 192 |
| 193 // The thread should now have stopped on its own. |
| 194 EXPECT_FALSE(a->IsRunning()); |
| 195 } |
| 196 |
| 197 TEST_F(ThreadTest, TwoTasksOnJoinableThread) { |
| 146 bool was_invoked = false; | 198 bool was_invoked = false; |
| 147 { | 199 { |
| 148 Thread a("TwoTasks"); | 200 Thread a("TwoTasksOnJoinableThread"); |
| 149 EXPECT_TRUE(a.Start()); | 201 EXPECT_TRUE(a.Start()); |
| 150 EXPECT_TRUE(a.message_loop()); | 202 EXPECT_TRUE(a.message_loop()); |
| 151 | 203 |
| 152 // Test that all events are dispatched before the Thread object is | 204 // Test that all events are dispatched before the Thread object is |
| 153 // destroyed. We do this by dispatching a sleep event before the | 205 // destroyed. We do this by dispatching a sleep event before the |
| 154 // event that will toggle our sentinel value. | 206 // event that will toggle our sentinel value. |
| 155 a.task_runner()->PostTask( | 207 a.task_runner()->PostTask( |
| 156 FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>( | 208 FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>( |
| 157 &base::PlatformThread::Sleep), | 209 &base::PlatformThread::Sleep), |
| 158 base::TimeDelta::FromMilliseconds(20))); | 210 base::TimeDelta::FromMilliseconds(20))); |
| 159 a.task_runner()->PostTask(FROM_HERE, | 211 a.task_runner()->PostTask(FROM_HERE, |
| 160 base::Bind(&ToggleValue, &was_invoked)); | 212 base::Bind(&ToggleValue, &was_invoked)); |
| 161 } | 213 } |
| 162 EXPECT_TRUE(was_invoked); | 214 EXPECT_TRUE(was_invoked); |
| 163 } | 215 } |
| 164 | 216 |
| 217 TEST_F(ThreadTest, DestroyWhileRunningIsSafe) { |
| 218 Thread a("DestroyWhileRunningIsSafe"); |
| 219 EXPECT_TRUE(a.Start()); |
| 220 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 221 } |
| 222 |
| 223 // TODO(gab): Enable this test when destroying a non-joinable Thread instance |
| 224 // is supported (proposal @ https://crbug.com/629139#c14). |
| 225 // TEST_F(ThreadTest, DestroyWhileRunningNonJoinableIsSafe) { |
| 226 // { |
| 227 // Thread a("DestroyWhileRunningNonJoinableIsSafe"); |
| 228 // Thread::Options options; |
| 229 // options.joinable = false; |
| 230 // EXPECT_TRUE(a.StartWithOptions(options)); |
| 231 // EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 232 // } |
| 233 // |
| 234 // // Attempt to catch use-after-frees from the non-joinable thread in the |
| 235 // // scope of this test if any. |
| 236 // base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 237 // } |
| 238 |
| 165 TEST_F(ThreadTest, StopSoon) { | 239 TEST_F(ThreadTest, StopSoon) { |
| 166 Thread a("StopSoon"); | 240 Thread a("StopSoon"); |
| 167 EXPECT_TRUE(a.Start()); | 241 EXPECT_TRUE(a.Start()); |
| 168 EXPECT_TRUE(a.message_loop()); | 242 EXPECT_TRUE(a.message_loop()); |
| 169 EXPECT_TRUE(a.IsRunning()); | 243 EXPECT_TRUE(a.IsRunning()); |
| 170 a.StopSoon(); | 244 a.StopSoon(); |
| 171 a.Stop(); | 245 a.Stop(); |
| 172 EXPECT_FALSE(a.message_loop()); | 246 EXPECT_FALSE(a.message_loop()); |
| 173 EXPECT_FALSE(a.IsRunning()); | 247 EXPECT_FALSE(a.IsRunning()); |
| 174 } | 248 } |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 207 | 281 |
| 208 EXPECT_TRUE(a.Start()); | 282 EXPECT_TRUE(a.Start()); |
| 209 EXPECT_TRUE(a.message_loop()); | 283 EXPECT_TRUE(a.message_loop()); |
| 210 EXPECT_TRUE(a.IsRunning()); | 284 EXPECT_TRUE(a.IsRunning()); |
| 211 | 285 |
| 212 a.Stop(); | 286 a.Stop(); |
| 213 EXPECT_FALSE(a.message_loop()); | 287 EXPECT_FALSE(a.message_loop()); |
| 214 EXPECT_FALSE(a.IsRunning()); | 288 EXPECT_FALSE(a.IsRunning()); |
| 215 } | 289 } |
| 216 | 290 |
| 291 TEST_F(ThreadTest, StartTwiceNonJoinableNotAllowed) { |
| 292 Thread* a = new Thread("StartTwiceNonJoinable"); |
| 293 // Non-joinable threads have to be leaked for now (see |
| 294 // Thread::Options::joinable for details). |
| 295 ANNOTATE_LEAKING_OBJECT_PTR(a); |
| 296 |
| 297 Thread::Options options; |
| 298 options.joinable = false; |
| 299 EXPECT_TRUE(a->StartWithOptions(options)); |
| 300 EXPECT_TRUE(a->message_loop()); |
| 301 EXPECT_TRUE(a->IsRunning()); |
| 302 |
| 303 // Signaled when last task on |a| is processed. |
| 304 base::WaitableEvent last_task_event( |
| 305 base::WaitableEvent::ResetPolicy::AUTOMATIC, |
| 306 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 307 a->task_runner()->PostTask(FROM_HERE, |
| 308 base::Bind(&base::WaitableEvent::Signal, |
| 309 base::Unretained(&last_task_event))); |
| 310 |
| 311 // StopSoon() is non-blocking, Yield() to |a|, wait for last task to be |
| 312 // processed and a little more for QuitWhenIdle() to unwind before considering |
| 313 // the thread "stopped". |
| 314 a->StopSoon(); |
| 315 base::PlatformThread::YieldCurrentThread(); |
| 316 last_task_event.Wait(); |
| 317 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20)); |
| 318 |
| 319 // This test assumes that the above was sufficient to let the thread fully |
| 320 // stop. |
| 321 ASSERT_FALSE(a->IsRunning()); |
| 322 |
| 323 // Restarting it should not be allowed. |
| 324 EXPECT_DCHECK_DEATH(a->Start(), ""); |
| 325 } |
| 326 |
| 217 TEST_F(ThreadTest, ThreadName) { | 327 TEST_F(ThreadTest, ThreadName) { |
| 218 Thread a("ThreadName"); | 328 Thread a("ThreadName"); |
| 219 EXPECT_TRUE(a.Start()); | 329 EXPECT_TRUE(a.Start()); |
| 220 EXPECT_EQ("ThreadName", a.thread_name()); | 330 EXPECT_EQ("ThreadName", a.thread_name()); |
| 221 } | 331 } |
| 222 | 332 |
| 223 TEST_F(ThreadTest, ThreadId) { | 333 TEST_F(ThreadTest, ThreadId) { |
| 224 Thread a("ThreadId0"); | 334 Thread a("ThreadId0"); |
| 225 Thread b("ThreadId1"); | 335 Thread b("ThreadId1"); |
| 226 a.Start(); | 336 a.Start(); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 EXPECT_FALSE(a.task_runner()); | 418 EXPECT_FALSE(a.task_runner()); |
| 309 } | 419 } |
| 310 | 420 |
| 311 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { | 421 TEST_F(ThreadTest, MultipleWaitUntilThreadStarted) { |
| 312 Thread a("MultipleWaitUntilThreadStarted"); | 422 Thread a("MultipleWaitUntilThreadStarted"); |
| 313 EXPECT_TRUE(a.Start()); | 423 EXPECT_TRUE(a.Start()); |
| 314 // It's OK to call WaitUntilThreadStarted() multiple times. | 424 // It's OK to call WaitUntilThreadStarted() multiple times. |
| 315 EXPECT_TRUE(a.WaitUntilThreadStarted()); | 425 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 316 EXPECT_TRUE(a.WaitUntilThreadStarted()); | 426 EXPECT_TRUE(a.WaitUntilThreadStarted()); |
| 317 } | 427 } |
| 428 |
| 429 namespace { |
| 430 |
| 431 // A Thread which uses a MessageLoop on the stack. It won't start a real |
| 432 // underlying thread (instead its messages can be processed by a RunLoop on the |
| 433 // stack). |
| 434 class ExternalMessageLoopThread : public Thread { |
| 435 public: |
| 436 ExternalMessageLoopThread() : Thread("ExternalMessageLoopThread") {} |
| 437 |
| 438 ~ExternalMessageLoopThread() override { Stop(); } |
| 439 |
| 440 void InstallMessageLoop() { SetMessageLoop(&external_message_loop_); } |
| 441 |
| 442 private: |
| 443 base::MessageLoop external_message_loop_; |
| 444 |
| 445 DISALLOW_COPY_AND_ASSIGN(ExternalMessageLoopThread); |
| 446 }; |
| 447 |
| 448 } // namespace |
| 449 |
| 450 TEST_F(ThreadTest, ExternalMessageLoop) { |
| 451 ExternalMessageLoopThread a; |
| 452 EXPECT_FALSE(a.message_loop()); |
| 453 EXPECT_FALSE(a.IsRunning()); |
| 454 |
| 455 a.InstallMessageLoop(); |
| 456 EXPECT_TRUE(a.message_loop()); |
| 457 EXPECT_TRUE(a.IsRunning()); |
| 458 |
| 459 bool ran = false; |
| 460 a.task_runner()->PostTask( |
| 461 FROM_HERE, base::Bind([](bool* toggled) { *toggled = true; }, &ran)); |
| 462 base::RunLoop().RunUntilIdle(); |
| 463 EXPECT_TRUE(ran); |
| 464 |
| 465 a.Stop(); |
| 466 EXPECT_FALSE(a.message_loop()); |
| 467 EXPECT_FALSE(a.IsRunning()); |
| 468 |
| 469 // Confirm that running any remaining tasks posted from Stop() goes smoothly |
| 470 // (e.g. https://codereview.chromium.org/2135413003/#ps300001 crashed if |
| 471 // StopSoon() posted Thread::ThreadQuitHelper() while |run_loop_| was null). |
| 472 base::RunLoop().RunUntilIdle(); |
| 473 } |
| OLD | NEW |