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

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: 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.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;
(...skipping 25 matching lines...) Expand all
67 if (com_status_ == STA) 68 if (com_status_ == STA)
68 options.message_loop_type = MessageLoop::TYPE_UI; 69 options.message_loop_type = MessageLoop::TYPE_UI;
69 #endif 70 #endif
70 return StartWithOptions(options); 71 return StartWithOptions(options);
71 } 72 }
72 73
73 bool Thread::StartWithOptions(const Options& options) { 74 bool Thread::StartWithOptions(const Options& options) {
74 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); 75 DCHECK(owning_sequence_checker_.CalledOnValidSequence());
75 DCHECK(!message_loop_); 76 DCHECK(!message_loop_);
76 DCHECK(!IsRunning()); 77 DCHECK(!IsRunning());
78 DCHECK(!stopping_) << "Starting a non-joinable thread a second time? That's "
79 << "not allowed!";
77 #if defined(OS_WIN) 80 #if defined(OS_WIN)
78 DCHECK((com_status_ != STA) || 81 DCHECK((com_status_ != STA) ||
79 (options.message_loop_type == MessageLoop::TYPE_UI)); 82 (options.message_loop_type == MessageLoop::TYPE_UI));
80 #endif 83 #endif
81 84
82 // Reset |id_| here to support restarting the thread. 85 // Reset |id_| here to support restarting the thread.
83 id_event_.Reset(); 86 id_event_.Reset();
84 id_ = kInvalidThreadId; 87 id_ = kInvalidThreadId;
85 88
86 SetThreadWasQuitProperly(false); 89 SetThreadWasQuitProperly(false);
87 90
88 MessageLoop::Type type = options.message_loop_type; 91 MessageLoop::Type type = options.message_loop_type;
89 if (!options.message_pump_factory.is_null()) 92 if (!options.message_pump_factory.is_null())
90 type = MessageLoop::TYPE_CUSTOM; 93 type = MessageLoop::TYPE_CUSTOM;
91 94
92 message_loop_timer_slack_ = options.timer_slack; 95 message_loop_timer_slack_ = options.timer_slack;
93 std::unique_ptr<MessageLoop> message_loop_owned = 96 std::unique_ptr<MessageLoop> message_loop_owned =
94 MessageLoop::CreateUnbound(type, options.message_pump_factory); 97 MessageLoop::CreateUnbound(type, options.message_pump_factory);
95 message_loop_ = message_loop_owned.get(); 98 message_loop_ = message_loop_owned.get();
96 start_event_.Reset(); 99 start_event_.Reset();
97 100
98 // Hold |thread_lock_| while starting the new thread to synchronize with 101 // 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 102 // Stop() while it's not guaranteed to be sequenced (until crbug/629139 is
100 // fixed). 103 // fixed).
101 { 104 {
102 AutoLock lock(thread_lock_); 105 AutoLock lock(thread_lock_);
103 if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_, 106 bool success =
104 options.priority)) { 107 options.joinable
108 ? PlatformThread::CreateWithPriority(options.stack_size, this,
109 &thread_, options.priority)
110 : PlatformThread::CreateNonJoinableWithPriority(
111 options.stack_size, this, options.priority);
112 if (!success) {
105 DLOG(ERROR) << "failed to create thread"; 113 DLOG(ERROR) << "failed to create thread";
106 message_loop_ = nullptr; 114 message_loop_ = nullptr;
107 return false; 115 return false;
108 } 116 }
109 } 117 }
110 118
119 joinable_ = options.joinable;
120
111 // The ownership of |message_loop_| is managed by the newly created thread 121 // The ownership of |message_loop_| is managed by the newly created thread
112 // within the ThreadMain. 122 // within the ThreadMain.
113 ignore_result(message_loop_owned.release()); 123 ignore_result(message_loop_owned.release());
114 124
115 DCHECK(message_loop_); 125 DCHECK(message_loop_);
116 return true; 126 return true;
117 } 127 }
118 128
119 bool Thread::StartAndWaitForTesting() { 129 bool Thread::StartAndWaitForTesting() {
120 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); 130 DCHECK(owning_sequence_checker_.CalledOnValidSequence());
121 bool result = Start(); 131 bool result = Start();
122 if (!result) 132 if (!result)
123 return false; 133 return false;
124 WaitUntilThreadStarted(); 134 WaitUntilThreadStarted();
125 return true; 135 return true;
126 } 136 }
127 137
128 bool Thread::WaitUntilThreadStarted() const { 138 bool Thread::WaitUntilThreadStarted() const {
129 DCHECK(owning_sequence_checker_.CalledOnValidSequence()); 139 DCHECK(owning_sequence_checker_.CalledOnValidSequence());
130 if (!message_loop_) 140 if (!message_loop_)
131 return false; 141 return false;
132 base::ThreadRestrictions::ScopedAllowWait allow_wait; 142 base::ThreadRestrictions::ScopedAllowWait allow_wait;
133 start_event_.Wait(); 143 start_event_.Wait();
134 return true; 144 return true;
135 } 145 }
136 146
137 void Thread::Stop() { 147 void Thread::Stop() {
148 DCHECK(joinable_);
149
138 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and 150 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and
139 // enable this check, until then synchronization with Start() via 151 // enable this check, until then synchronization with Start() via
140 // |thread_lock_| is required... 152 // |thread_lock_| is required...
141 // DCHECK(owning_sequence_checker_.CalledOnValidSequence()); 153 // DCHECK(owning_sequence_checker_.CalledOnValidSequence());
142 AutoLock lock(thread_lock_); 154 AutoLock lock(thread_lock_);
143 155
156 StopSoon();
157
158 // Can't join if the |thread_| is either already gone or is non-joinable.
144 if (thread_.is_null()) 159 if (thread_.is_null())
145 return; 160 return;
146 161
147 StopSoon();
148
149 // Wait for the thread to exit. 162 // Wait for the thread to exit.
150 // 163 //
151 // TODO(darin): Unfortunately, we need to keep |message_loop_| around until 164 // TODO(darin): Unfortunately, we need to keep |message_loop_| around until
152 // the thread exits. Some consumers are abusing the API. Make them stop. 165 // the thread exits. Some consumers are abusing the API. Make them stop.
153 // 166 //
154 PlatformThread::Join(thread_); 167 PlatformThread::Join(thread_);
155 thread_ = base::PlatformThreadHandle(); 168 thread_ = base::PlatformThreadHandle();
156 169
157 // The thread should nullify |message_loop_| on exit (note: Join() adds an 170 // 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). 171 // implicit memory barrier and no lock is thus required for this check).
159 DCHECK(!message_loop_); 172 DCHECK(!message_loop_);
160 173
161 stopping_ = false; 174 stopping_ = false;
162 } 175 }
163 176
164 void Thread::StopSoon() { 177 void Thread::StopSoon() {
165 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and 178 // TODO(gab): Fix improper usage of this API (http://crbug.com/629139) and
166 // enable this check. 179 // enable this check.
167 // DCHECK(owning_sequence_checker_.CalledOnValidSequence()); 180 // DCHECK(owning_sequence_checker_.CalledOnValidSequence());
168 181
169 if (stopping_ || !message_loop_) 182 if (stopping_ || !message_loop_)
170 return; 183 return;
171 184
172 stopping_ = true; 185 stopping_ = true;
186
187 if (using_external_message_loop_) {
188 // Setting |stopping_| to true above should have been sufficient for this
189 // thread to be considered "stopped" per it having never set its |running_|
190 // bit by lack of its own ThreadMain.
191 DCHECK(!IsRunning());
192 message_loop_ = nullptr;
193 return;
194 }
195
173 task_runner()->PostTask( 196 task_runner()->PostTask(
174 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this))); 197 FROM_HERE, base::Bind(&Thread::ThreadQuitHelper, Unretained(this)));
175 } 198 }
176 199
177 PlatformThreadId Thread::GetThreadId() const { 200 PlatformThreadId Thread::GetThreadId() const {
178 // If the thread is created but not started yet, wait for |id_| being ready. 201 // If the thread is created but not started yet, wait for |id_| being ready.
179 base::ThreadRestrictions::ScopedAllowWait allow_wait; 202 base::ThreadRestrictions::ScopedAllowWait allow_wait;
180 id_event_.Wait(); 203 id_event_.Wait();
181 return id_; 204 return id_;
182 } 205 }
(...skipping 29 matching lines...) Expand all
212 235
213 // static 236 // static
214 bool Thread::GetThreadWasQuitProperly() { 237 bool Thread::GetThreadWasQuitProperly() {
215 bool quit_properly = true; 238 bool quit_properly = true;
216 #ifndef NDEBUG 239 #ifndef NDEBUG
217 quit_properly = lazy_tls_bool.Pointer()->Get(); 240 quit_properly = lazy_tls_bool.Pointer()->Get();
218 #endif 241 #endif
219 return quit_properly; 242 return quit_properly;
220 } 243 }
221 244
245 void Thread::SetMessageLoop(MessageLoop* message_loop) {
246 DCHECK(owning_sequence_checker_.CalledOnValidSequence());
247
248 // TODO(gab): Figure out why some callers pass in a null |message_loop|...
249 // https://crbug.com/629139#c15
250 // DCHECK(message_loop);
251 if (!message_loop)
252 return;
253
254 // Setting |message_loop_| should suffice for this thread to be considered
255 // as "running", until Stop() is invoked.
256 DCHECK(!IsRunning());
257 message_loop_ = message_loop;
258 DCHECK(IsRunning());
259
260 using_external_message_loop_ = true;
261 }
262
222 void Thread::ThreadMain() { 263 void Thread::ThreadMain() {
223 // First, make GetThreadId() available to avoid deadlocks. It could be called 264 // First, make GetThreadId() available to avoid deadlocks. It could be called
224 // any place in the following thread initialization code. 265 // any place in the following thread initialization code.
225 id_ = PlatformThread::CurrentId(); 266 id_ = PlatformThread::CurrentId();
226 DCHECK_NE(kInvalidThreadId, id_); 267 DCHECK_NE(kInvalidThreadId, id_);
227 id_event_.Signal(); 268 id_event_.Signal();
228 269
229 // Complete the initialization of our Thread object. 270 // Complete the initialization of our Thread object.
230 PlatformThread::SetName(name_.c_str()); 271 PlatformThread::SetName(name_.c_str());
231 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. 272 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 run_loop_ = nullptr; 325 run_loop_ = nullptr;
285 } 326 }
286 327
287 void Thread::ThreadQuitHelper() { 328 void Thread::ThreadQuitHelper() {
288 DCHECK(run_loop_); 329 DCHECK(run_loop_);
289 run_loop_->QuitWhenIdle(); 330 run_loop_->QuitWhenIdle();
290 SetThreadWasQuitProperly(true); 331 SetThreadWasQuitProperly(true);
291 } 332 }
292 333
293 } // namespace base 334 } // 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