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

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: ignore SetMessageLoop(nullptr) for now -- added TODO 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
« no previous file with comments | « base/threading/thread.cc ('k') | content/browser/browser_thread_impl.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « base/threading/thread.cc ('k') | content/browser/browser_thread_impl.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698