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

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

Issue 1180693002: Update from https://crrev.com/333737 (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: rebased Created 5 years, 6 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_id_name_manager_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/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/location.h" 9 #include "base/location.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
12 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 11 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
13 #include "base/threading/thread_id_name_manager.h" 12 #include "base/threading/thread_id_name_manager.h"
14 #include "base/threading/thread_local.h" 13 #include "base/threading/thread_local.h"
15 #include "base/threading/thread_restrictions.h" 14 #include "base/threading/thread_restrictions.h"
16 15
17 #if defined(OS_WIN) 16 #if defined(OS_WIN)
18 #include "base/win/scoped_com_initializer.h" 17 #include "base/win/scoped_com_initializer.h"
19 #endif 18 #endif
20 19
21 namespace base { 20 namespace base {
22 21
23 namespace { 22 namespace {
24 23
25 // We use this thread-local variable to record whether or not a thread exited 24 // 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 25 // because its Stop method was called. This allows us to catch cases where
27 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when 26 // MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
28 // using a Thread to setup and run a MessageLoop. 27 // using a Thread to setup and run a MessageLoop.
29 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool = 28 base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
30 LAZY_INSTANCE_INITIALIZER; 29 LAZY_INSTANCE_INITIALIZER;
31 30
32 } // namespace 31 } // namespace
33 32
34 // This is used to trigger the message loop to exit. 33 // This is used to trigger the message loop to exit.
35 void ThreadQuitHelper() { 34 void ThreadQuitHelper() {
36 MessageLoop::current()->QuitWhenIdle(); 35 MessageLoop::current()->QuitWhenIdle();
37 Thread::SetThreadWasQuitProperly(true); 36 Thread::SetThreadWasQuitProperly(true);
38 } 37 }
39 38
40 // Used to pass data to ThreadMain. This structure is allocated on the stack
41 // from within StartWithOptions.
42 struct Thread::StartupData {
43 // We get away with a const reference here because of how we are allocated.
44 const Thread::Options& options;
45
46 // Used to synchronize thread startup.
47 WaitableEvent event;
48
49 explicit StartupData(const Options& opt)
50 : options(opt),
51 event(false, false) {}
52 };
53
54 Thread::Options::Options() 39 Thread::Options::Options()
55 : message_loop_type(MessageLoop::TYPE_DEFAULT), 40 : message_loop_type(MessageLoop::TYPE_DEFAULT),
56 timer_slack(TIMER_SLACK_NONE), 41 timer_slack(TIMER_SLACK_NONE),
57 stack_size(0) { 42 stack_size(0),
43 priority(ThreadPriority::NORMAL) {
58 } 44 }
59 45
60 Thread::Options::Options(MessageLoop::Type type, 46 Thread::Options::Options(MessageLoop::Type type,
61 size_t size) 47 size_t size)
62 : message_loop_type(type), 48 : message_loop_type(type),
63 timer_slack(TIMER_SLACK_NONE), 49 timer_slack(TIMER_SLACK_NONE),
64 stack_size(size) { 50 stack_size(size),
51 priority(ThreadPriority::NORMAL) {
65 } 52 }
66 53
67 Thread::Options::~Options() { 54 Thread::Options::~Options() {
68 } 55 }
69 56
70 Thread::Thread(const std::string& name) 57 Thread::Thread(const std::string& name)
71 : 58 :
72 #if defined(OS_WIN) 59 #if defined(OS_WIN)
73 com_status_(NONE), 60 com_status_(NONE),
74 #endif 61 #endif
75 started_(false),
76 stopping_(false), 62 stopping_(false),
77 running_(false), 63 running_(false),
78 startup_data_(NULL),
79 thread_(0), 64 thread_(0),
80 message_loop_(NULL), 65 message_loop_(nullptr),
81 thread_id_(kInvalidThreadId), 66 message_loop_timer_slack_(TIMER_SLACK_NONE),
82 name_(name) { 67 name_(name) {
83 } 68 }
84 69
85 Thread::~Thread() { 70 Thread::~Thread() {
86 Stop(); 71 Stop();
87 } 72 }
88 73
89 bool Thread::Start() { 74 bool Thread::Start() {
90 Options options; 75 Options options;
91 #if defined(OS_WIN) 76 #if defined(OS_WIN)
92 if (com_status_ == STA) 77 if (com_status_ == STA)
93 options.message_loop_type = MessageLoop::TYPE_UI; 78 options.message_loop_type = MessageLoop::TYPE_UI;
94 #endif 79 #endif
95 return StartWithOptions(options); 80 return StartWithOptions(options);
96 } 81 }
97 82
98 bool Thread::StartWithOptions(const Options& options) { 83 bool Thread::StartWithOptions(const Options& options) {
99 DCHECK(!message_loop_); 84 DCHECK(!message_loop_);
100 #if defined(OS_WIN) 85 #if defined(OS_WIN)
101 DCHECK((com_status_ != STA) || 86 DCHECK((com_status_ != STA) ||
102 (options.message_loop_type == MessageLoop::TYPE_UI)); 87 (options.message_loop_type == MessageLoop::TYPE_UI));
103 #endif 88 #endif
104 89
105 SetThreadWasQuitProperly(false); 90 SetThreadWasQuitProperly(false);
106 91
107 StartupData startup_data(options); 92 MessageLoop::Type type = options.message_loop_type;
108 startup_data_ = &startup_data; 93 if (!options.message_pump_factory.is_null())
94 type = MessageLoop::TYPE_CUSTOM;
109 95
110 if (!PlatformThread::Create(options.stack_size, this, &thread_)) { 96 message_loop_timer_slack_ = options.timer_slack;
111 DLOG(ERROR) << "failed to create thread"; 97 message_loop_ = new MessageLoop(type, options.message_pump_factory);
112 startup_data_ = NULL; 98
113 return false; 99 start_event_.reset(new WaitableEvent(false, false));
100
101 // Hold the thread_lock_ while starting a new thread, so that we can make sure
102 // that thread_ is populated before the newly created thread accesses it.
103 {
104 AutoLock lock(thread_lock_);
105 bool created;
106 if (options.priority == ThreadPriority::NORMAL) {
107 created = PlatformThread::Create(options.stack_size, this, &thread_);
108 } else {
109 created = PlatformThread::CreateWithPriority(options.stack_size, this,
110 &thread_, options.priority);
111 }
112 if (!created) {
113 DLOG(ERROR) << "failed to create thread";
114 delete message_loop_;
115 message_loop_ = nullptr;
116 start_event_.reset();
117 return false;
118 }
114 } 119 }
115 120
116 // TODO(kinuko): Remove once crbug.com/465458 is solved.
117 tracked_objects::ScopedTracker tracking_profile_wait(
118 FROM_HERE_WITH_EXPLICIT_FUNCTION(
119 "465458 base::Thread::StartWithOptions (Wait)"));
120
121 // Wait for the thread to start and initialize message_loop_
122 base::ThreadRestrictions::ScopedAllowWait allow_wait;
123 startup_data.event.Wait();
124
125 // set it to NULL so we don't keep a pointer to some object on the stack.
126 startup_data_ = NULL;
127 started_ = true;
128
129 DCHECK(message_loop_); 121 DCHECK(message_loop_);
130 return true; 122 return true;
131 } 123 }
132 124
125 bool Thread::StartAndWaitForTesting() {
126 bool result = Start();
127 if (!result)
128 return false;
129 WaitUntilThreadStarted();
130 return true;
131 }
132
133 bool Thread::WaitUntilThreadStarted() {
134 if (!start_event_)
135 return false;
136 base::ThreadRestrictions::ScopedAllowWait allow_wait;
137 start_event_->Wait();
138 return true;
139 }
140
133 void Thread::Stop() { 141 void Thread::Stop() {
134 if (!started_) 142 if (!start_event_)
135 return; 143 return;
136 144
137 StopSoon(); 145 StopSoon();
138 146
139 // Wait for the thread to exit. 147 // Wait for the thread to exit.
140 // 148 //
141 // TODO(darin): Unfortunately, we need to keep message_loop_ around until 149 // TODO(darin): Unfortunately, we need to keep message_loop_ around until
142 // the thread exits. Some consumers are abusing the API. Make them stop. 150 // the thread exits. Some consumers are abusing the API. Make them stop.
143 // 151 //
144 PlatformThread::Join(thread_); 152 PlatformThread::Join(thread_);
145 153
146 // The thread should NULL message_loop_ on exit. 154 // The thread should NULL message_loop_ on exit.
147 DCHECK(!message_loop_); 155 DCHECK(!message_loop_);
148 156
149 // The thread no longer needs to be joined. 157 // The thread no longer needs to be joined.
150 started_ = false; 158 start_event_.reset();
151 159
152 stopping_ = false; 160 stopping_ = false;
153 } 161 }
154 162
155 void Thread::StopSoon() { 163 void Thread::StopSoon() {
156 // We should only be called on the same thread that started us. 164 // We should only be called on the same thread that started us.
157 165
158 // Reading thread_id_ without a lock can lead to a benign data race 166 DCHECK_NE(thread_id(), PlatformThread::CurrentId());
159 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
160 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
161 167
162 if (stopping_ || !message_loop_) 168 if (stopping_ || !message_loop_)
163 return; 169 return;
164 170
165 stopping_ = true; 171 stopping_ = true;
166 task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper)); 172 task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
167 } 173 }
168 174
175 PlatformThreadId Thread::thread_id() const {
176 AutoLock lock(thread_lock_);
177 return thread_.id();
178 }
179
169 bool Thread::IsRunning() const { 180 bool Thread::IsRunning() const {
181 // If the thread's already started (i.e. message_loop_ is non-null) and
182 // not yet requested to stop (i.e. stopping_ is false) we can just return
183 // true. (Note that stopping_ is touched only on the same thread that
184 // starts / started the new thread so we need no locking here.)
185 if (message_loop_ && !stopping_)
186 return true;
187 // Otherwise check the running_ flag, which is set to true by the new thread
188 // only while it is inside Run().
189 AutoLock lock(running_lock_);
170 return running_; 190 return running_;
171 } 191 }
172 192
173 void Thread::SetPriority(ThreadPriority priority) { 193 void Thread::SetPriority(ThreadPriority priority) {
174 // The thread must be started (and id known) for this to be 194 // The thread must be started (and id known) for this to be
175 // compatible with all platforms. 195 // compatible with all platforms.
176 DCHECK_NE(thread_id_, kInvalidThreadId); 196 DCHECK(message_loop_ != nullptr);
177 PlatformThread::SetThreadPriority(thread_, priority); 197 PlatformThread::SetThreadPriority(thread_, priority);
178 } 198 }
179 199
180 void Thread::Run(MessageLoop* message_loop) { 200 void Thread::Run(MessageLoop* message_loop) {
181 message_loop->Run(); 201 message_loop->Run();
182 } 202 }
183 203
184 void Thread::SetThreadWasQuitProperly(bool flag) { 204 void Thread::SetThreadWasQuitProperly(bool flag) {
185 lazy_tls_bool.Pointer()->Set(flag); 205 lazy_tls_bool.Pointer()->Set(flag);
186 } 206 }
187 207
188 bool Thread::GetThreadWasQuitProperly() { 208 bool Thread::GetThreadWasQuitProperly() {
189 bool quit_properly = true; 209 bool quit_properly = true;
190 #ifndef NDEBUG 210 #ifndef NDEBUG
191 quit_properly = lazy_tls_bool.Pointer()->Get(); 211 quit_properly = lazy_tls_bool.Pointer()->Get();
192 #endif 212 #endif
193 return quit_properly; 213 return quit_properly;
194 } 214 }
195 215
196 void Thread::ThreadMain() { 216 void Thread::ThreadMain() {
197 { 217 // Complete the initialization of our Thread object.
198 // The message loop for this thread. 218 PlatformThread::SetName(name_.c_str());
199 // Allocated on the heap to centralize any leak reports at this line. 219 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
200 scoped_ptr<MessageLoop> message_loop;
201 if (!startup_data_->options.message_pump_factory.is_null()) {
202 message_loop.reset(
203 new MessageLoop(startup_data_->options.message_pump_factory.Run()));
204 } else {
205 message_loop.reset(
206 new MessageLoop(startup_data_->options.message_loop_type));
207 }
208 220
209 // Complete the initialization of our Thread object. 221 // Lazily initialize the message_loop so that it can run on this thread.
210 thread_id_ = PlatformThread::CurrentId(); 222 DCHECK(message_loop_);
211 PlatformThread::SetName(name_); 223 scoped_ptr<MessageLoop> message_loop(message_loop_);
212 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. 224 message_loop_->BindToCurrentThread();
213 message_loop->set_thread_name(name_); 225 message_loop_->set_thread_name(name_);
214 message_loop->SetTimerSlack(startup_data_->options.timer_slack); 226 message_loop_->SetTimerSlack(message_loop_timer_slack_);
215 message_loop_ = message_loop.get();
216 227
217 #if defined(OS_WIN) 228 #if defined(OS_WIN)
218 scoped_ptr<win::ScopedCOMInitializer> com_initializer; 229 scoped_ptr<win::ScopedCOMInitializer> com_initializer;
219 if (com_status_ != NONE) { 230 if (com_status_ != NONE) {
220 com_initializer.reset((com_status_ == STA) ? 231 com_initializer.reset((com_status_ == STA) ?
221 new win::ScopedCOMInitializer() : 232 new win::ScopedCOMInitializer() :
222 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA)); 233 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
223 } 234 }
224 #endif 235 #endif
225 236
226 // Let the thread do extra initialization. 237 // Make sure the thread_id() returns current thread.
227 // Let's do this before signaling we are started. 238 // (This internally acquires lock against PlatformThread::Create)
228 Init(); 239 DCHECK_EQ(thread_id(), PlatformThread::CurrentId());
229 240
241 // Let the thread do extra initialization.
242 Init();
243
244 {
245 AutoLock lock(running_lock_);
230 running_ = true; 246 running_ = true;
231 startup_data_->event.Signal(); 247 }
232 // startup_data_ can't be touched anymore since the starting thread is now
233 // unlocked.
234 248
235 Run(message_loop_); 249 start_event_->Signal();
250
251 Run(message_loop_);
252
253 {
254 AutoLock lock(running_lock_);
236 running_ = false; 255 running_ = false;
256 }
237 257
238 // Let the thread do extra cleanup. 258 // Let the thread do extra cleanup.
239 CleanUp(); 259 CleanUp();
240 260
241 #if defined(OS_WIN) 261 #if defined(OS_WIN)
242 com_initializer.reset(); 262 com_initializer.reset();
243 #endif 263 #endif
244 264
245 // Assert that MessageLoop::Quit was called by ThreadQuitHelper. 265 // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
246 DCHECK(GetThreadWasQuitProperly()); 266 DCHECK(GetThreadWasQuitProperly());
247 267
248 // We can't receive messages anymore. 268 // We can't receive messages anymore.
249 message_loop_ = NULL; 269 // (The message loop is destructed at the end of this block)
250 } 270 message_loop_ = NULL;
251 } 271 }
252 272
253 } // namespace base 273 } // namespace base
OLDNEW
« no previous file with comments | « base/threading/thread.h ('k') | base/threading/thread_id_name_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698