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

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

Issue 1058603004: [Approach 3] Pre-allocate IncomigTaskQueue before MessageLoop for faster thread startup Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 8 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/message_loop/incoming_task_queue.h"
9 #include "base/profiler/scoped_tracker.h" 10 #include "base/profiler/scoped_tracker.h"
10 #include "base/synchronization/waitable_event.h" 11 #include "base/synchronization/waitable_event.h"
11 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 12 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
12 #include "base/threading/thread_id_name_manager.h" 13 #include "base/threading/thread_id_name_manager.h"
13 #include "base/threading/thread_local.h" 14 #include "base/threading/thread_local.h"
14 #include "base/threading/thread_restrictions.h" 15 #include "base/threading/thread_restrictions.h"
15 16
16 #if defined(OS_WIN) 17 #if defined(OS_WIN)
17 #include "base/win/scoped_com_initializer.h" 18 #include "base/win/scoped_com_initializer.h"
18 #endif 19 #endif
(...skipping 10 matching lines...) Expand all
29 LAZY_INSTANCE_INITIALIZER; 30 LAZY_INSTANCE_INITIALIZER;
30 31
31 } // namespace 32 } // namespace
32 33
33 // This is used to trigger the message loop to exit. 34 // This is used to trigger the message loop to exit.
34 void ThreadQuitHelper() { 35 void ThreadQuitHelper() {
35 MessageLoop::current()->QuitWhenIdle(); 36 MessageLoop::current()->QuitWhenIdle();
36 Thread::SetThreadWasQuitProperly(true); 37 Thread::SetThreadWasQuitProperly(true);
37 } 38 }
38 39
39 // Used to pass data to ThreadMain. This structure is allocated on the stack 40 // Provides TaskRunner interface on top of IncomingTaskQueue.
40 // from within StartWithOptions. 41 class Thread::IncomingTaskQueueRunner : public SingleThreadTaskRunner {
41 struct Thread::StartupData { 42 public:
42 // We get away with a const reference here because of how we are allocated. 43 IncomingTaskQueueRunner()
43 const Thread::Options& options; 44 : incoming_task_queue_(new internal::IncomingTaskQueue()),
45 valid_thread_id_(kInvalidThreadId) {}
44 46
45 // Used to synchronize thread startup. 47 void AttachThread() {
46 WaitableEvent event; 48 valid_thread_id_ = PlatformThread::CurrentId();
49 }
47 50
48 explicit StartupData(const Options& opt) 51 internal::IncomingTaskQueue* incoming_task_queue() {
49 : options(opt), 52 return incoming_task_queue_.get();
50 event(false, false) {} 53 }
54
55 protected:
56 ~IncomingTaskQueueRunner() override {}
57
58 // TaskRunner override:
59 bool PostDelayedTask(const tracked_objects::Location& from_here,
60 const Closure& task,
61 base::TimeDelta delay) override {
62 DCHECK(!task.is_null()) << from_here.ToString();
63 return incoming_task_queue_->AddToIncomingQueue(
64 from_here, task, delay, true);
65 }
66
67 bool RunsTasksOnCurrentThread() const override {
68 return valid_thread_id_ == PlatformThread::CurrentId();
69 }
70
71 // SequencedTaskRunner override:
72 bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
73 const Closure& task,
74 base::TimeDelta delay) override {
75 DCHECK(!task.is_null()) << from_here.ToString();
76 return incoming_task_queue_->AddToIncomingQueue(
77 from_here, task, delay, false);
78 }
79
80 private:
81 scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
82
83 // ID of the thread the task posted to this runner should run.
84 PlatformThreadId valid_thread_id_;
51 }; 85 };
52 86
53 Thread::Options::Options() 87 Thread::Options::Options()
54 : message_loop_type(MessageLoop::TYPE_DEFAULT), 88 : message_loop_type(MessageLoop::TYPE_DEFAULT),
55 timer_slack(TIMER_SLACK_NONE), 89 timer_slack(TIMER_SLACK_NONE),
56 stack_size(0) { 90 stack_size(0) {
57 } 91 }
58 92
59 Thread::Options::Options(MessageLoop::Type type, 93 Thread::Options::Options(MessageLoop::Type type,
60 size_t size) 94 size_t size)
61 : message_loop_type(type), 95 : message_loop_type(type),
62 timer_slack(TIMER_SLACK_NONE), 96 timer_slack(TIMER_SLACK_NONE),
63 stack_size(size) { 97 stack_size(size) {
64 } 98 }
65 99
66 Thread::Options::~Options() { 100 Thread::Options::~Options() {
67 } 101 }
68 102
69 Thread::Thread(const std::string& name) 103 Thread::Thread(const std::string& name)
70 : 104 :
71 #if defined(OS_WIN) 105 #if defined(OS_WIN)
72 com_status_(NONE), 106 com_status_(NONE),
73 #endif 107 #endif
74 started_(false),
75 stopping_(false), 108 stopping_(false),
76 running_(false), 109 running_(false),
77 startup_data_(NULL),
78 thread_(0), 110 thread_(0),
79 message_loop_(NULL), 111 message_loop_(nullptr),
80 thread_id_(kInvalidThreadId),
81 name_(name) { 112 name_(name) {
82 } 113 }
83 114
84 Thread::~Thread() { 115 Thread::~Thread() {
85 Stop(); 116 Stop();
86 } 117 }
87 118
88 bool Thread::Start() { 119 bool Thread::Start() {
89 Options options; 120 Options options;
90 #if defined(OS_WIN) 121 #if defined(OS_WIN)
91 if (com_status_ == STA) 122 if (com_status_ == STA)
92 options.message_loop_type = MessageLoop::TYPE_UI; 123 options.message_loop_type = MessageLoop::TYPE_UI;
93 #endif 124 #endif
94 return StartWithOptions(options); 125 return StartWithOptions(options);
95 } 126 }
96 127
97 bool Thread::StartWithOptions(const Options& options) { 128 bool Thread::StartWithOptions(const Options& options) {
98 DCHECK(!message_loop_); 129 DCHECK(!message_loop_);
99 #if defined(OS_WIN) 130 #if defined(OS_WIN)
100 DCHECK((com_status_ != STA) || 131 DCHECK((com_status_ != STA) ||
101 (options.message_loop_type == MessageLoop::TYPE_UI)); 132 (options.message_loop_type == MessageLoop::TYPE_UI));
102 #endif 133 #endif
103 134
104 SetThreadWasQuitProperly(false); 135 SetThreadWasQuitProperly(false);
105 136
106 StartupData startup_data(options); 137 task_runner_ = new IncomingTaskQueueRunner();
107 startup_data_ = &startup_data; 138
139 startup_data_.reset(new Options(options));
140 start_event_.reset(new WaitableEvent(false, false));
108 141
109 if (!PlatformThread::Create(options.stack_size, this, &thread_)) { 142 if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
110 DLOG(ERROR) << "failed to create thread"; 143 DLOG(ERROR) << "failed to create thread";
111 startup_data_ = NULL; 144 start_event_.reset();
112 return false; 145 return false;
113 } 146 }
114 147
148 return true;
149 }
150
151 bool Thread::StartAndWait() {
152 bool result = Start();
153 if (!result)
154 return result;
155 WaitUntilThreadStarted();
156 return result;
157 }
158
159 bool Thread::WaitUntilThreadStarted() {
160 if (!start_event_)
161 return false;
115 // TODO(kinuko): Remove once crbug.com/465458 is solved. 162 // TODO(kinuko): Remove once crbug.com/465458 is solved.
116 tracked_objects::ScopedTracker tracking_profile_wait( 163 tracked_objects::ScopedTracker tracking_profile(
117 FROM_HERE_WITH_EXPLICIT_FUNCTION( 164 FROM_HERE_WITH_EXPLICIT_FUNCTION(
118 "465458 base::Thread::StartWithOptions (Wait)")); 165 "465458 base::Thread::WaitUntilThreadStarted()"));
119
120 // Wait for the thread to start and initialize message_loop_
121 base::ThreadRestrictions::ScopedAllowWait allow_wait; 166 base::ThreadRestrictions::ScopedAllowWait allow_wait;
122 startup_data.event.Wait(); 167 start_event_->Wait();
123
124 // set it to NULL so we don't keep a pointer to some object on the stack.
125 startup_data_ = NULL;
126 started_ = true;
127
128 DCHECK(message_loop_);
129 return true; 168 return true;
130 } 169 }
131 170
132 void Thread::Stop() { 171 void Thread::Stop() {
133 if (!started_) 172 if (!start_event_)
134 return; 173 return;
135 174
136 StopSoon(); 175 StopSoon();
137 176
138 // Wait for the thread to exit. 177 // Wait for the thread to exit.
139 // 178 //
140 // TODO(darin): Unfortunately, we need to keep message_loop_ around until 179 // TODO(darin): Unfortunately, we need to keep message_loop_ around until
141 // the thread exits. Some consumers are abusing the API. Make them stop. 180 // the thread exits. Some consumers are abusing the API. Make them stop.
142 // 181 //
143 PlatformThread::Join(thread_); 182 PlatformThread::Join(thread_);
144 183
145 // The thread should NULL message_loop_ on exit. 184 // The thread should NULL message_loop_ on exit.
146 DCHECK(!message_loop_); 185 DCHECK(!message_loop_);
147 186
148 // The thread no longer needs to be joined. 187 // The thread no longer needs to be joined.
149 started_ = false; 188 start_event_.reset();
150 189
151 stopping_ = false; 190 stopping_ = false;
152 } 191 }
153 192
154 void Thread::StopSoon() { 193 void Thread::StopSoon() {
155 // We should only be called on the same thread that started us. 194 // We should only be called on the same thread that started us.
156 195
157 // Reading thread_id_ without a lock can lead to a benign data race 196 DCHECK_NE(thread_id(), PlatformThread::CurrentId());
158 // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
159 DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
160 197
161 if (stopping_ || !message_loop_) 198 if (stopping_ || !start_event_)
162 return; 199 return;
163 200
164 stopping_ = true; 201 stopping_ = true;
165 message_loop_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper)); 202 task_runner_->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
166 } 203 }
167 204
168 bool Thread::IsRunning() const { 205 bool Thread::IsRunning() const {
206 if (start_event_ && !stopping_)
207 return true;
208 AutoLock lock(lock_);
169 return running_; 209 return running_;
170 } 210 }
171 211
172 void Thread::SetPriority(ThreadPriority priority) { 212 void Thread::SetPriority(ThreadPriority priority) {
173 // The thread must be started (and id known) for this to be 213 // The thread must be started (and id known) for this to be
174 // compatible with all platforms. 214 // compatible with all platforms.
175 DCHECK_NE(thread_id_, kInvalidThreadId); 215 DCHECK(!!start_event_);
176 PlatformThread::SetThreadPriority(thread_, priority); 216 PlatformThread::SetThreadPriority(thread_, priority);
177 } 217 }
178 218
179 void Thread::Run(MessageLoop* message_loop) { 219 void Thread::Run(MessageLoop* message_loop) {
180 message_loop->Run(); 220 message_loop->Run();
181 } 221 }
182 222
183 void Thread::SetThreadWasQuitProperly(bool flag) { 223 void Thread::SetThreadWasQuitProperly(bool flag) {
184 lazy_tls_bool.Pointer()->Set(flag); 224 lazy_tls_bool.Pointer()->Set(flag);
185 } 225 }
186 226
187 bool Thread::GetThreadWasQuitProperly() { 227 bool Thread::GetThreadWasQuitProperly() {
188 bool quit_properly = true; 228 bool quit_properly = true;
189 #ifndef NDEBUG 229 #ifndef NDEBUG
190 quit_properly = lazy_tls_bool.Pointer()->Get(); 230 quit_properly = lazy_tls_bool.Pointer()->Get();
191 #endif 231 #endif
192 return quit_properly; 232 return quit_properly;
193 } 233 }
194 234
195 void Thread::ThreadMain() { 235 void Thread::ThreadMain() {
196 { 236 IncomingTaskQueueRunner* incoming_task_queue_runner =
197 // The message loop for this thread. 237 static_cast<IncomingTaskQueueRunner*>(task_runner_.get());
198 // Allocated on the heap to centralize any leak reports at this line.
199 scoped_ptr<MessageLoop> message_loop;
200 if (!startup_data_->options.message_pump_factory.is_null()) {
201 message_loop.reset(
202 new MessageLoop(startup_data_->options.message_pump_factory.Run()));
203 } else {
204 message_loop.reset(
205 new MessageLoop(startup_data_->options.message_loop_type));
206 }
207 238
208 // Complete the initialization of our Thread object. 239 // The message loop for this thread.
209 thread_id_ = PlatformThread::CurrentId(); 240 // Allocated on the heap to centralize any leak reports at this line.
210 PlatformThread::SetName(name_.c_str()); 241 scoped_ptr<MessageLoop> message_loop;
211 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector. 242 MessageLoop::Options options;
212 message_loop->set_thread_name(name_); 243 options.message_loop_type = startup_data_->message_loop_type;
213 message_loop->SetTimerSlack(startup_data_->options.timer_slack); 244 options.message_pump_factory = startup_data_->message_pump_factory;
214 message_loop_ = message_loop.get(); 245 options.incoming_task_queue =
246 incoming_task_queue_runner->incoming_task_queue();
247 message_loop.reset(new MessageLoop(options));
248
249 incoming_task_queue_runner->AttachThread();
250
251 // Complete the initialization of our Thread object.
252 DCHECK_EQ(thread_id(), PlatformThread::CurrentId());
253 PlatformThread::SetName(name_.c_str());
254 ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
255 message_loop->set_thread_name(name_);
256 message_loop->SetTimerSlack(startup_data_->timer_slack);
257 message_loop_ = message_loop.get();
258
259 startup_data_.reset();
215 260
216 #if defined(OS_WIN) 261 #if defined(OS_WIN)
217 scoped_ptr<win::ScopedCOMInitializer> com_initializer; 262 scoped_ptr<win::ScopedCOMInitializer> com_initializer;
218 if (com_status_ != NONE) { 263 if (com_status_ != NONE) {
219 com_initializer.reset((com_status_ == STA) ? 264 com_initializer.reset((com_status_ == STA) ?
220 new win::ScopedCOMInitializer() : 265 new win::ScopedCOMInitializer() :
221 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA)); 266 new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
222 } 267 }
223 #endif 268 #endif
224 269
225 // Let the thread do extra initialization. 270 // Let the thread do extra initialization.
226 // Let's do this before signaling we are started. 271 Init();
227 Init();
228 272
273 {
274 AutoLock lock(lock_);
229 running_ = true; 275 running_ = true;
230 startup_data_->event.Signal(); 276 }
231 // startup_data_ can't be touched anymore since the starting thread is now
232 // unlocked.
233 277
234 Run(message_loop_); 278 start_event_->Signal();
279
280 Run(message_loop_);
281
282 {
283 AutoLock lock(lock_);
235 running_ = false; 284 running_ = false;
285 }
236 286
237 // Let the thread do extra cleanup. 287 // Let the thread do extra cleanup.
238 CleanUp(); 288 CleanUp();
239 289
240 #if defined(OS_WIN) 290 #if defined(OS_WIN)
241 com_initializer.reset(); 291 com_initializer.reset();
242 #endif 292 #endif
243 293
244 // Assert that MessageLoop::Quit was called by ThreadQuitHelper. 294 // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
245 DCHECK(GetThreadWasQuitProperly()); 295 DCHECK(GetThreadWasQuitProperly());
246 296
247 // We can't receive messages anymore. 297 // We can't receive messages anymore.
248 message_loop_ = NULL; 298 // (The message loop is destructed at the end of this block)
249 } 299 message_loop_ = NULL;
250 } 300 }
251 301
252 } // namespace base 302 } // 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