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

Side by Side Diff: base/threading/thread.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
« no previous file with comments | « base/threading/thread.h ('k') | base/threading/thread_unittest.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 "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/logging.h"
11 #include "base/run_loop.h" 12 #include "base/run_loop.h"
12 #include "base/synchronization/waitable_event.h" 13 #include "base/synchronization/waitable_event.h"
13 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 14 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
14 #include "base/threading/thread_id_name_manager.h" 15 #include "base/threading/thread_id_name_manager.h"
15 #include "base/threading/thread_local.h" 16 #include "base/threading/thread_local.h"
16 #include "base/threading/thread_restrictions.h" 17 #include "base/threading/thread_restrictions.h"
17 #include "build/build_config.h" 18 #include "build/build_config.h"
18 19
19 #if defined(OS_WIN) 20 #if defined(OS_WIN)
20 #include "base/win/scoped_com_initializer.h" 21 #include "base/win/scoped_com_initializer.h"
21 #endif 22 #endif
22 23
23 namespace base { 24 namespace base {
24 25
25 namespace { 26 namespace {
26 27
27 // We use this thread-local variable to record whether or not a thread exited 28 // We use this thread-local variable to record whether or not a thread exited
28 // because its Stop method was called. This allows us to catch cases where 29 // because its Stop method was called. This allows us to catch cases where
29 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when 30 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
30 // using a Thread to setup and run a MessageLoop. 31 // using a Thread to setup and run a MessageLoop.
31 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = 32 base::LazyInstance<base::ThreadLocalBoolean>::Leaky lazy_tls_bool =
32 LAZY_INSTANCE_INITIALIZER; 33 LAZY_INSTANCE_INITIALIZER;
33 34
34 } // namespace 35 } // namespace
35 36
36 Thread::Options::Options() = default; 37 Thread::Options::Options() = default;
37 38
38 Thread::Options::Options(MessageLoop::Type type, size_t size) 39 Thread::Options::Options(MessageLoop::Type type, size_t size)
39 : message_loop_type(type), stack_size(size) {} 40 : message_loop_type(type), stack_size(size) {}
40 41
41 Thread::Options::Options(const Options& other) = default; 42 Thread::Options::Options(const Options& other) = default;
42 43
43 Thread::Options::~Options() = default; 44 Thread::Options::~Options() = default;
44 45
45 Thread::Thread(const std::string& name) 46 Thread::Thread(const std::string& name)
46 : id_event_(WaitableEvent::ResetPolicy::MANUAL, 47 : id_event_(WaitableEvent::ResetPolicy::MANUAL,
47 WaitableEvent::InitialState::NOT_SIGNALED), 48 WaitableEvent::InitialState::NOT_SIGNALED),
48 name_(name), 49 name_(name),
49 start_event_(WaitableEvent::ResetPolicy::MANUAL, 50 start_event_(WaitableEvent::ResetPolicy::MANUAL,
50 WaitableEvent::InitialState::NOT_SIGNALED) { 51 WaitableEvent::InitialState::NOT_SIGNALED) {
51 // Only bind the sequence on Start(): the state is constant between 52 // Only bind the sequence on Start(): the state is constant between
52 // construction and Start() and it's thus valid for Start() to be called on 53 // construction and Start() and it's thus valid for Start() to be called on
53 // another sequence as long as every other operation is then performed on that 54 // another sequence as long as every other operation is then performed on that
54 // sequence. 55 // sequence.
55 owning_sequence_checker_.DetachFromSequence(); 56 owning_sequence_checker_.DetachFromSequence();
56 } 57 }
57 58
58 Thread::~Thread() { 59 Thread::~Thread() {
59 Stop(); 60 Stop();
61
62 // ThreadMain() must have returned before this Thread instance is destroyed
63 // or use-after-frees could ensue.
64 DCHECK(!thread_main_exited_.get() || thread_main_exited_->IsSet());
danakj 2016/07/28 19:07:40 no .get()
gab 2016/07/28 21:40:15 I intentionally added the .get()'s here and below
60 } 65 }
61 66
62 bool Thread::Start() { 67 bool Thread::Start() {
63 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); 68 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread());
64 69
65 Options options; 70 Options options;
66 #if defined(OS_WIN) 71 #if defined(OS_WIN)
67 if (com_status_ == STA) 72 if (com_status_ == STA)
68 options.message_loop_type = MessageLoop::TYPE_UI; 73 options.message_loop_type = MessageLoop::TYPE_UI;
69 #endif 74 #endif
70 return StartWithOptions(options); 75 return StartWithOptions(options);
71 } 76 }
72 77
73 bool Thread::StartWithOptions(const Options& options) { 78 bool Thread::StartWithOptions(const Options& options) {
74 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); 79 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread());
75 DCHECK(!message_loop_); 80 DCHECK(!message_loop_);
76 DCHECK(!IsRunning()); 81 DCHECK(!IsRunning());
82 DCHECK(!stopping_) << "Starting a non-joinable thread a second time? That's "
83 << "not allowed!";
77 #if defined(OS_WIN) 84 #if defined(OS_WIN)
78 DCHECK((com_status_ != STA) || 85 DCHECK((com_status_ != STA) ||
79 (options.message_loop_type == MessageLoop::TYPE_UI)); 86 (options.message_loop_type == MessageLoop::TYPE_UI));
80 #endif 87 #endif
81 88
82 // Reset |id_| here to support restarting the thread. 89 // Reset |id_| here to support restarting the thread.
83 id_event_.Reset(); 90 id_event_.Reset();
84 id_ = kInvalidThreadId; 91 id_ = kInvalidThreadId;
85 92
93 if (!thread_main_exited_.get()) {
danakj 2016/07/28 19:07:40 no .get()
gab 2016/07/28 21:40:15 Similarly here: if (!thread_main_exited_) feels
94 thread_main_exited_.reset(new AtomicFlag);
95 } else {
96 // It's safe to reset |thread_main_exited_| on sequence when the underlying
97 // thread isn't running.
98 thread_main_exited_->UnsafeReset();
99 }
100
86 SetThreadWasQuitProperly(false); 101 SetThreadWasQuitProperly(false);
87 102
88 MessageLoop::Type type = options.message_loop_type; 103 MessageLoop::Type type = options.message_loop_type;
89 if (!options.message_pump_factory.is_null()) 104 if (!options.message_pump_factory.is_null())
90 type = MessageLoop::TYPE_CUSTOM; 105 type = MessageLoop::TYPE_CUSTOM;
91 106
92 message_loop_timer_slack_ = options.timer_slack; 107 message_loop_timer_slack_ = options.timer_slack;
93 std::unique_ptr<MessageLoop> message_loop_owned = 108 std::unique_ptr<MessageLoop> message_loop_owned =
94 MessageLoop::CreateUnbound(type, options.message_pump_factory); 109 MessageLoop::CreateUnbound(type, options.message_pump_factory);
95 message_loop_ = message_loop_owned.get(); 110 message_loop_ = message_loop_owned.get();
96 start_event_.Reset(); 111 start_event_.Reset();
97 112
98 // Hold |thread_lock_| while starting the new thread to synchronize with 113 // Hold |thread_lock_| while starting the new thread to synchronize with
99 // Stop() while it's not guaranteed to be sequenced (until crbug/629139 is 114 // Stop() while it's not guaranteed to be sequenced (until crbug/629139 is
100 // fixed). 115 // fixed).
101 { 116 {
102 AutoLock lock(thread_lock_); 117 AutoLock lock(thread_lock_);
103 if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_, 118 bool success =
104 options.priority)) { 119 options.joinable
120 ? PlatformThread::CreateWithPriority(options.stack_size, this,
121 &thread_, options.priority)
122 : PlatformThread::CreateNonJoinableWithPriority(
123 options.stack_size, this, options.priority);
124 if (!success) {
105 DLOG(ERROR) << "failed to create thread"; 125 DLOG(ERROR) << "failed to create thread";
106 message_loop_ = nullptr; 126 message_loop_ = nullptr;
107 return false; 127 return false;
108 } 128 }
109 } 129 }
110 130
111 // The ownership of |message_loop_| is managed by the newly created thread 131 // The ownership of |message_loop_| is managed by the newly created thread
112 // within the ThreadMain. 132 // within the ThreadMain.
113 ignore_result(message_loop_owned.release()); 133 ignore_result(message_loop_owned.release());
114 134
(...skipping 19 matching lines...) Expand all
134 return true; 154 return true;
135 } 155 }
136 156
137 void Thread::Stop() { 157 void Thread::Stop() {
138 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and 158 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and
139 // enable this check, until then synchronization with Start() via 159 // enable this check, until then synchronization with Start() via
140 // |thread_lock_| is required... 160 // |thread_lock_| is required...
141 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); 161 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread());
142 AutoLock lock(thread_lock_); 162 AutoLock lock(thread_lock_);
143 163
164 StopSoon();
165
166 // Can't join if the |thread_| is either already gone or is non-joinable.
144 if (thread_.is_null()) 167 if (thread_.is_null())
145 return; 168 return;
146 169
147 StopSoon();
148
149 // Wait for the thread to exit. 170 // Wait for the thread to exit.
150 // 171 //
151 // TODO(darin): Unfortunately, we need to keep |message_loop_| around until 172 // TODO(darin): Unfortunately, we need to keep |message_loop_| around until
152 // the thread exits. Some consumers are abusing the API. Make them stop. 173 // the thread exits. Some consumers are abusing the API. Make them stop.
153 // 174 //
154 PlatformThread::Join(thread_); 175 PlatformThread::Join(thread_);
155 thread_ = base::PlatformThreadHandle(); 176 thread_ = base::PlatformThreadHandle();
156 177
157 // The thread should nullify |message_loop_| on exit (note: Join() adds an 178 // The thread should nullify |message_loop_| on exit (note: Join() adds an
158 // implicit memory barrier and no lock is thus required for this check). 179 // implicit memory barrier and no lock is thus required for this check).
159 DCHECK(!message_loop_); 180 DCHECK(!message_loop_);
160 181
161 stopping_ = false; 182 stopping_ = false;
162 } 183 }
163 184
164 void Thread::StopSoon() { 185 void Thread::StopSoon() {
165 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and 186 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and
166 // enable this check. 187 // enable this check.
167 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread()); 188 // DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread());
168 189
169 if (stopping_ || !message_loop_) 190 if (stopping_ || !message_loop_)
170 return; 191 return;
171 192
172 stopping_ = true; 193 stopping_ = true;
194
195 if (using_external_message_loop_) {
196 // Setting |stopping_| to true above should have been sufficient for this
197 // thread to be considered "stopped" per it having never set its |running_|
198 // bit by lack of its own ThreadMain.
199 DCHECK(!IsRunning());
200 message_loop_ = nullptr;
201 return;
202 }
203
173 task_runner()->PostTask( 204 task_runner()->PostTask(
174 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this))); 205 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this)));
175 } 206 }
176 207
177 PlatformThreadId Thread::GetThreadId() const { 208 PlatformThreadId Thread::GetThreadId() const {
178 // If the thread is created but not started yet, wait for |id_| being ready. 209 // If the thread is created but not started yet, wait for |id_| being ready.
179 base::ThreadRestrictions::ScopedAllowWait allow_wait; 210 base::ThreadRestrictions::ScopedAllowWait allow_wait;
180 id_event_.Wait(); 211 id_event_.Wait();
181 return id_; 212 return id_;
182 } 213 }
(...skipping 29 matching lines...) Expand all
212 243
213 // static 244 // static
214 bool Thread::GetThreadWasQuitProperly() { 245 bool Thread::GetThreadWasQuitProperly() {
215 bool quit_properly = true; 246 bool quit_properly = true;
216 #ifndef NDEBUG 247 #ifndef NDEBUG
217 quit_properly = lazy_tls_bool.Pointer()->Get(); 248 quit_properly = lazy_tls_bool.Pointer()->Get();
218 #endif 249 #endif
219 return quit_properly; 250 return quit_properly;
220 } 251 }
221 252
253 void Thread::SetMessageLoop(MessageLoop* message_loop) {
254 DCHECK(owning_sequence_checker_.CalledOnValidSequencedThread());
255
256 // Setting |message_loop_| should suffice for this thread to be considered
257 // as "running", until Stop() is invoked.
258 DCHECK(!IsRunning());
259 message_loop_ = message_loop;
260 DCHECK(IsRunning());
261
262 using_external_message_loop_ = true;
263 }
264
222 void Thread::ThreadMain() { 265 void Thread::ThreadMain() {
223 // First, make GetThreadId() available to avoid deadlocks. It could be called 266 // First, make GetThreadId() available to avoid deadlocks. It could be called
224 // any place in the following thread initialization code. 267 // any place in the following thread initialization code.
225 id_ = PlatformThread::CurrentId(); 268 id_ = PlatformThread::CurrentId();
226 DCHECK_NE(kInvalidThreadId, id_); 269 DCHECK_NE(kInvalidThreadId, id_);
227 id_event_.Signal(); 270 id_event_.Signal();
228 271
229 // Complete the initialization of our Thread object. 272 // Complete the initialization of our Thread object.
230 PlatformThread::SetName(name_.c_str()); 273 PlatformThread::SetName(name_.c_str());
231 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. 274 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
275 // Assert that RunLoop::QuitWhenIdle was called by ThreadQuitHelper. Don't 318 // Assert that RunLoop::QuitWhenIdle was called by ThreadQuitHelper. Don't
276 // check for custom message pumps, because their shutdown might not allow 319 // check for custom message pumps, because their shutdown might not allow
277 // this. 320 // this.
278 DCHECK(GetThreadWasQuitProperly()); 321 DCHECK(GetThreadWasQuitProperly());
279 } 322 }
280 323
281 // We can't receive messages anymore. 324 // We can't receive messages anymore.
282 // (The message loop is destructed at the end of this block) 325 // (The message loop is destructed at the end of this block)
283 message_loop_ = nullptr; 326 message_loop_ = nullptr;
284 run_loop_ = nullptr; 327 run_loop_ = nullptr;
328
329 thread_main_exited_->Set();
285 } 330 }
286 331
287 void Thread::ThreadQuitHelper() { 332 void Thread::ThreadQuitHelper() {
288 DCHECK(run_loop_); 333 DCHECK(run_loop_);
289 run_loop_->QuitWhenIdle(); 334 run_loop_->QuitWhenIdle();
290 SetThreadWasQuitProperly(true); 335 SetThreadWasQuitProperly(true);
291 } 336 }
292 337
293 } // namespace base 338 } // namespace base
OLDNEW
« no previous file with comments | « base/threading/thread.h ('k') | base/threading/thread_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698