Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(239)

Side by Side Diff: base/threading/thread_unittest.cc

Issue 2135413003: Add |joinable| to Thread::Options (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: update dependent CL Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698