blob: 229ef154a90171b6aaeafb0f86ebdf4dd950c9c9 [file] [log] [blame]
[email protected]06c0c062012-05-21 18:49:371// Copyright (c) 2012 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]34b99632011-01-01 01:01:065#include "base/threading/thread.h"
[email protected]eff4aecb2008-08-12 18:37:356
[email protected]6e238ba2011-11-23 20:45:437#include "base/bind.h"
[email protected]f886b7bf2008-09-10 10:54:068#include "base/lazy_instance.h"
skyostil054861d2015-04-30 19:06:159#include "base/location.h"
eromanf653ac3a2015-03-10 01:06:1910#include "base/synchronization/waitable_event.h"
[email protected]ee857512010-05-14 08:24:4211#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
[email protected]7d342e882013-01-25 20:41:1912#include "base/threading/thread_id_name_manager.h"
[email protected]1357c322010-12-30 22:18:5613#include "base/threading/thread_local.h"
[email protected]3a7b66d2012-04-26 16:34:1614#include "base/threading/thread_restrictions.h"
avi9ceb8b82015-12-24 21:53:5915#include "build/build_config.h"
[email protected]eff4aecb2008-08-12 18:37:3516
[email protected]458e9522012-10-23 04:33:5217#if defined(OS_WIN)
18#include "base/win/scoped_com_initializer.h"
19#endif
20
[email protected]4d9bdfaf2008-08-26 05:53:5721namespace base {
22
[email protected]eae9c062011-01-11 00:50:5923namespace {
24
25// We use this thread-local variable to record whether or not a thread exited
26// because its Stop method was called. This allows us to catch cases where
[email protected]91cae2592013-01-10 14:56:1727// MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
28// using a Thread to setup and run a MessageLoop.
[email protected]6de0fd1d2011-11-15 13:31:4929base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
30 LAZY_INSTANCE_INITIALIZER;
[email protected]eae9c062011-01-11 00:50:5931
32} // namespace
33
[email protected]6e238ba2011-11-23 20:45:4334// This is used to trigger the message loop to exit.
35void ThreadQuitHelper() {
[email protected]91cae2592013-01-10 14:56:1736 MessageLoop::current()->QuitWhenIdle();
[email protected]6e238ba2011-11-23 20:45:4337 Thread::SetThreadWasQuitProperly(true);
38}
initial.commitd7cae122008-07-26 21:49:3839
[email protected]9f0e4f72013-11-08 06:16:5340Thread::Options::Options()
41 : message_loop_type(MessageLoop::TYPE_DEFAULT),
[email protected]8a3e4e12014-06-24 19:51:0242 timer_slack(TIMER_SLACK_NONE),
toyoshim66f71ec2015-06-09 06:37:0643 stack_size(0),
44 priority(ThreadPriority::NORMAL) {
[email protected]9f0e4f72013-11-08 06:16:5345}
46
47Thread::Options::Options(MessageLoop::Type type,
48 size_t size)
49 : message_loop_type(type),
[email protected]8a3e4e12014-06-24 19:51:0250 timer_slack(TIMER_SLACK_NONE),
toyoshim66f71ec2015-06-09 06:37:0651 stack_size(size),
52 priority(ThreadPriority::NORMAL) {
[email protected]9f0e4f72013-11-08 06:16:5353}
54
vmpstre65942b2016-02-25 00:50:3155Thread::Options::Options(const Options& other) = default;
56
[email protected]9f0e4f72013-11-08 06:16:5357Thread::Options::~Options() {
58}
59
[email protected]f6c8a6a72014-04-18 23:32:4060Thread::Thread(const std::string& name)
[email protected]458e9522012-10-23 04:33:5261 :
62#if defined(OS_WIN)
63 com_status_(NONE),
64#endif
[email protected]a0297bd52010-07-23 05:32:3865 stopping_(false),
[email protected]06c0c062012-05-21 18:49:3766 running_(false),
[email protected]65487262008-08-26 06:06:0167 thread_(0),
toyoshimc41261e2015-07-24 09:25:1668 id_(kInvalidThreadId),
gab75d72332016-06-01 21:15:3369 id_event_(WaitableEvent::ResetPolicy::MANUAL,
70 WaitableEvent::InitialState::NOT_SIGNALED),
kinuko7f68f872015-05-23 11:38:3771 message_loop_(nullptr),
72 message_loop_timer_slack_(TIMER_SLACK_NONE),
toyoshim53818d552015-08-06 09:03:0873 name_(name),
gab75d72332016-06-01 21:15:3374 start_event_(WaitableEvent::ResetPolicy::MANUAL,
75 WaitableEvent::InitialState::NOT_SIGNALED) {
initial.commitd7cae122008-07-26 21:49:3876}
77
78Thread::~Thread() {
79 Stop();
80}
81
initial.commitd7cae122008-07-26 21:49:3882bool Thread::Start() {
[email protected]458e9522012-10-23 04:33:5283 Options options;
84#if defined(OS_WIN)
85 if (com_status_ == STA)
86 options.message_loop_type = MessageLoop::TYPE_UI;
87#endif
88 return StartWithOptions(options);
initial.commitd7cae122008-07-26 21:49:3889}
90
[email protected]4d9bdfaf2008-08-26 05:53:5791bool Thread::StartWithOptions(const Options& options) {
[email protected]e9ba26d2008-08-21 09:46:3292 DCHECK(!message_loop_);
[email protected]458e9522012-10-23 04:33:5293#if defined(OS_WIN)
94 DCHECK((com_status_ != STA) ||
95 (options.message_loop_type == MessageLoop::TYPE_UI));
96#endif
initial.commitd7cae122008-07-26 21:49:3897
toyoshimc41261e2015-07-24 09:25:1698 // Reset |id_| here to support restarting the thread.
99 id_event_.Reset();
100 id_ = kInvalidThreadId;
101
[email protected]e9ba26d2008-08-21 09:46:32102 SetThreadWasQuitProperly(false);
103
kinuko7f68f872015-05-23 11:38:37104 MessageLoop::Type type = options.message_loop_type;
105 if (!options.message_pump_factory.is_null())
106 type = MessageLoop::TYPE_CUSTOM;
[email protected]e9ba26d2008-08-21 09:46:32107
kinuko7f68f872015-05-23 11:38:37108 message_loop_timer_slack_ = options.timer_slack;
dcheng093de9b2016-04-04 21:25:51109 std::unique_ptr<MessageLoop> message_loop =
110 MessageLoop::CreateUnbound(type, options.message_pump_factory);
kinuko547a48b2015-06-30 01:31:54111 message_loop_ = message_loop.get();
toyoshim53818d552015-08-06 09:03:08112 start_event_.Reset();
kinuko7f68f872015-05-23 11:38:37113
114 // Hold the thread_lock_ while starting a new thread, so that we can make sure
115 // that thread_ is populated before the newly created thread accesses it.
116 {
117 AutoLock lock(thread_lock_);
toyoshim9f3199f2015-07-18 09:49:33118 if (!PlatformThread::CreateWithPriority(options.stack_size, this, &thread_,
119 options.priority)) {
kinuko7f68f872015-05-23 11:38:37120 DLOG(ERROR) << "failed to create thread";
kinuko7f68f872015-05-23 11:38:37121 message_loop_ = nullptr;
kinuko7f68f872015-05-23 11:38:37122 return false;
123 }
initial.commitd7cae122008-07-26 21:49:38124 }
125
kinuko547a48b2015-06-30 01:31:54126 // The ownership of message_loop is managemed by the newly created thread
127 // within the ThreadMain.
128 ignore_result(message_loop.release());
129
[email protected]e9ba26d2008-08-21 09:46:32130 DCHECK(message_loop_);
initial.commitd7cae122008-07-26 21:49:38131 return true;
132}
133
kinuko7f68f872015-05-23 11:38:37134bool Thread::StartAndWaitForTesting() {
135 bool result = Start();
136 if (!result)
137 return false;
138 WaitUntilThreadStarted();
139 return true;
140}
141
toyoshim53818d552015-08-06 09:03:08142bool Thread::WaitUntilThreadStarted() const {
143 if (!message_loop_)
kinuko7f68f872015-05-23 11:38:37144 return false;
145 base::ThreadRestrictions::ScopedAllowWait allow_wait;
toyoshim53818d552015-08-06 09:03:08146 start_event_.Wait();
kinuko7f68f872015-05-23 11:38:37147 return true;
148}
149
initial.commitd7cae122008-07-26 21:49:38150void Thread::Stop() {
toyoshim53818d552015-08-06 09:03:08151 AutoLock lock(thread_lock_);
152 if (thread_.is_null())
initial.commitd7cae122008-07-26 21:49:38153 return;
154
[email protected]88f333122009-09-14 23:47:38155 StopSoon();
initial.commitd7cae122008-07-26 21:49:38156
[email protected]88f333122009-09-14 23:47:38157 // Wait for the thread to exit.
[email protected]4d9bdfaf2008-08-26 05:53:57158 //
159 // TODO(darin): Unfortunately, we need to keep message_loop_ around until
160 // the thread exits. Some consumers are abusing the API. Make them stop.
161 //
[email protected]e9ba26d2008-08-21 09:46:32162 PlatformThread::Join(thread_);
toyoshim53818d552015-08-06 09:03:08163 thread_ = base::PlatformThreadHandle();
[email protected]eff4aecb2008-08-12 18:37:35164
toyoshim53818d552015-08-06 09:03:08165 // The thread should nullify message_loop_ on exit.
[email protected]88f333122009-09-14 23:47:38166 DCHECK(!message_loop_);
[email protected]e9ba26d2008-08-21 09:46:32167
[email protected]88f333122009-09-14 23:47:38168 stopping_ = false;
[email protected]eff4aecb2008-08-12 18:37:35169}
170
171void Thread::StopSoon() {
[email protected]4d9bdfaf2008-08-26 05:53:57172 // We should only be called on the same thread that started us.
[email protected]1b3b50682010-05-19 08:44:48173
toyoshimc41261e2015-07-24 09:25:16174 DCHECK_NE(GetThreadId(), PlatformThread::CurrentId());
[email protected]eff4aecb2008-08-12 18:37:35175
[email protected]3c92e242009-09-21 17:03:46176 if (stopping_ || !message_loop_)
[email protected]88f333122009-09-14 23:47:38177 return;
initial.commitd7cae122008-07-26 21:49:38178
[email protected]88f333122009-09-14 23:47:38179 stopping_ = true;
skyostil054861d2015-04-30 19:06:15180 task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
initial.commitd7cae122008-07-26 21:49:38181}
182
toyoshimc41261e2015-07-24 09:25:16183PlatformThreadId Thread::GetThreadId() const {
184 // If the thread is created but not started yet, wait for |id_| being ready.
185 base::ThreadRestrictions::ScopedAllowWait allow_wait;
186 id_event_.Wait();
187 return id_;
kinuko7f68f872015-05-23 11:38:37188}
189
[email protected]06c0c062012-05-21 18:49:37190bool Thread::IsRunning() const {
kinuko7f68f872015-05-23 11:38:37191 // If the thread's already started (i.e. message_loop_ is non-null) and
192 // not yet requested to stop (i.e. stopping_ is false) we can just return
193 // true. (Note that stopping_ is touched only on the same thread that
194 // starts / started the new thread so we need no locking here.)
195 if (message_loop_ && !stopping_)
196 return true;
197 // Otherwise check the running_ flag, which is set to true by the new thread
198 // only while it is inside Run().
199 AutoLock lock(running_lock_);
[email protected]06c0c062012-05-21 18:49:37200 return running_;
201}
202
[email protected]828bd792009-09-10 05:00:20203void Thread::Run(MessageLoop* message_loop) {
204 message_loop->Run();
205}
206
[email protected]eae9c062011-01-11 00:50:59207void Thread::SetThreadWasQuitProperly(bool flag) {
208 lazy_tls_bool.Pointer()->Set(flag);
209}
210
211bool Thread::GetThreadWasQuitProperly() {
212 bool quit_properly = true;
213#ifndef NDEBUG
214 quit_properly = lazy_tls_bool.Pointer()->Get();
215#endif
216 return quit_properly;
217}
218
[email protected]e9ba26d2008-08-21 09:46:32219void Thread::ThreadMain() {
toyoshimc41261e2015-07-24 09:25:16220 // First, make GetThreadId() available to avoid deadlocks. It could be called
221 // any place in the following thread initialization code.
222 id_ = PlatformThread::CurrentId();
223 DCHECK_NE(kInvalidThreadId, id_);
224 id_event_.Signal();
225
kinuko7f68f872015-05-23 11:38:37226 // Complete the initialization of our Thread object.
227 PlatformThread::SetName(name_.c_str());
228 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
initial.commitd7cae122008-07-26 21:49:38229
kinuko7f68f872015-05-23 11:38:37230 // Lazily initialize the message_loop so that it can run on this thread.
231 DCHECK(message_loop_);
dcheng093de9b2016-04-04 21:25:51232 std::unique_ptr<MessageLoop> message_loop(message_loop_);
kinuko7f68f872015-05-23 11:38:37233 message_loop_->BindToCurrentThread();
234 message_loop_->set_thread_name(name_);
235 message_loop_->SetTimerSlack(message_loop_timer_slack_);
[email protected]e9ba26d2008-08-21 09:46:32236
[email protected]458e9522012-10-23 04:33:52237#if defined(OS_WIN)
dcheng093de9b2016-04-04 21:25:51238 std::unique_ptr<win::ScopedCOMInitializer> com_initializer;
kinuko7f68f872015-05-23 11:38:37239 if (com_status_ != NONE) {
240 com_initializer.reset((com_status_ == STA) ?
241 new win::ScopedCOMInitializer() :
242 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
glider787e3342015-05-18 13:24:19243 }
kinuko7f68f872015-05-23 11:38:37244#endif
245
kinuko7f68f872015-05-23 11:38:37246 // Let the thread do extra initialization.
247 Init();
248
249 {
250 AutoLock lock(running_lock_);
251 running_ = true;
252 }
253
toyoshim53818d552015-08-06 09:03:08254 start_event_.Signal();
kinuko7f68f872015-05-23 11:38:37255
256 Run(message_loop_);
257
258 {
259 AutoLock lock(running_lock_);
260 running_ = false;
261 }
262
263 // Let the thread do extra cleanup.
264 CleanUp();
265
266#if defined(OS_WIN)
267 com_initializer.reset();
268#endif
269
John Abd-El-Maleka6342a92015-11-24 06:29:56270 if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
271 // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.
272 // Don't check for custom message pumps, because their shutdown might not
273 // allow this.
274 DCHECK(GetThreadWasQuitProperly());
275 }
kinuko7f68f872015-05-23 11:38:37276
277 // We can't receive messages anymore.
278 // (The message loop is destructed at the end of this block)
toyoshim53818d552015-08-06 09:03:08279 message_loop_ = nullptr;
initial.commitd7cae122008-07-26 21:49:38280}
license.botbf09a502008-08-24 00:55:55281
[email protected]4d9bdfaf2008-08-26 05:53:57282} // namespace base