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

Side by Side Diff: base/message_loop/message_loop.cc

Issue 17567007: Made MessagePump a non-thread safe class. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: IncomingTaskQueue Created 7 years, 5 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/message_loop/message_loop.h" 5 #include "base/message_loop/message_loop.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
11 #include "base/debug/alias.h" 11 #include "base/debug/alias.h"
12 #include "base/debug/trace_event.h" 12 #include "base/debug/trace_event.h"
13 #include "base/lazy_instance.h" 13 #include "base/lazy_instance.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_ptr.h"
16 #include "base/message_loop/message_loop_proxy_impl.h"
17 #include "base/message_loop/message_pump_default.h" 16 #include "base/message_loop/message_pump_default.h"
18 #include "base/metrics/histogram.h" 17 #include "base/metrics/histogram.h"
19 #include "base/metrics/statistics_recorder.h" 18 #include "base/metrics/statistics_recorder.h"
20 #include "base/run_loop.h" 19 #include "base/run_loop.h"
21 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" 20 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
22 #include "base/thread_task_runner_handle.h" 21 #include "base/thread_task_runner_handle.h"
23 #include "base/threading/thread_local.h" 22 #include "base/threading/thread_local.h"
24 #include "base/time/time.h" 23 #include "base/time/time.h"
25 #include "base/tracked_objects.h" 24 #include "base/tracked_objects.h"
26 25
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) 81 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) 82 VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
84 83
85 {-1, NULL} // The list must be null terminated, per API to histogram. 84 {-1, NULL} // The list must be null terminated, per API to histogram.
86 }; 85 };
87 86
88 bool enable_histogrammer_ = false; 87 bool enable_histogrammer_ = false;
89 88
90 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; 89 MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
91 90
92 // Create a process-wide unique ID to represent this task in trace events. This
93 // will be mangled with a Process ID hash to reduce the likelyhood of colliding
94 // with MessageLoop pointers on other processes.
95 uint64 GetTaskTraceID(const PendingTask& task, MessageLoop* loop) {
96 return (static_cast<uint64>(task.sequence_num) << 32) |
97 static_cast<uint64>(reinterpret_cast<intptr_t>(loop));
98 }
99
100 } // namespace 91 } // namespace
101 92
102 //------------------------------------------------------------------------------ 93 //------------------------------------------------------------------------------
103 94
104 #if defined(OS_WIN) 95 #if defined(OS_WIN)
105 96
106 // Upon a SEH exception in this thread, it restores the original unhandled 97 // Upon a SEH exception in this thread, it restores the original unhandled
107 // exception filter. 98 // exception filter.
108 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { 99 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
109 ::SetUnhandledExceptionFilter(old_filter); 100 ::SetUnhandledExceptionFilter(old_filter);
(...skipping 19 matching lines...) Expand all
129 MessageLoop::TaskObserver::~TaskObserver() { 120 MessageLoop::TaskObserver::~TaskObserver() {
130 } 121 }
131 122
132 MessageLoop::DestructionObserver::~DestructionObserver() { 123 MessageLoop::DestructionObserver::~DestructionObserver() {
133 } 124 }
134 125
135 //------------------------------------------------------------------------------ 126 //------------------------------------------------------------------------------
136 127
137 MessageLoop::MessageLoop(Type type) 128 MessageLoop::MessageLoop(Type type)
138 : type_(type), 129 : type_(type),
130 exception_restoration_(false),
139 nestable_tasks_allowed_(true), 131 nestable_tasks_allowed_(true),
140 exception_restoration_(false),
141 message_histogram_(NULL),
142 run_loop_(NULL),
143 #if defined(OS_WIN) 132 #if defined(OS_WIN)
144 os_modal_loop_(false), 133 os_modal_loop_(false),
145 #endif // OS_WIN 134 #endif // OS_WIN
146 next_sequence_num_(0) { 135 message_histogram_(NULL),
136 run_loop_(NULL) {
147 DCHECK(!current()) << "should only have one message loop per thread"; 137 DCHECK(!current()) << "should only have one message loop per thread";
148 lazy_tls_ptr.Pointer()->Set(this); 138 lazy_tls_ptr.Pointer()->Set(this);
149 139
150 message_loop_proxy_ = new MessageLoopProxyImpl(); 140 incoming_task_queue_ = new internal::IncomingTaskQueue();
141 message_loop_proxy_ =
142 new internal::MessageLoopProxyImpl(incoming_task_queue_);
151 thread_task_runner_handle_.reset( 143 thread_task_runner_handle_.reset(
152 new ThreadTaskRunnerHandle(message_loop_proxy_)); 144 new ThreadTaskRunnerHandle(message_loop_proxy_));
153 145
154 // TODO(rvargas): Get rid of the OS guards. 146 // TODO(rvargas): Get rid of the OS guards.
155 #if defined(OS_WIN) 147 #if defined(OS_WIN)
156 #define MESSAGE_PUMP_UI new MessagePumpForUI() 148 #define MESSAGE_PUMP_UI new MessagePumpForUI()
157 #define MESSAGE_PUMP_IO new MessagePumpForIO() 149 #define MESSAGE_PUMP_IO new MessagePumpForIO()
158 #elif defined(OS_IOS) 150 #elif defined(OS_IOS)
159 #define MESSAGE_PUMP_UI MessagePumpMac::Create() 151 #define MESSAGE_PUMP_UI MessagePumpMac::Create()
160 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO() 152 #define MESSAGE_PUMP_IO new MessagePumpIOSForIO()
161 #elif defined(OS_MACOSX) 153 #elif defined(OS_MACOSX)
162 #define MESSAGE_PUMP_UI MessagePumpMac::Create() 154 #define MESSAGE_PUMP_UI MessagePumpMac::Create()
163 #define MESSAGE_PUMP_IO new MessagePumpLibevent() 155 #define MESSAGE_PUMP_IO new MessagePumpLibevent()
164 #elif defined(OS_NACL) 156 #elif defined(OS_NACL)
165 // Currently NaCl doesn't have a UI MessageLoop. 157 // Currently NaCl doesn't have a UI MessageLoop.
166 // TODO(abarth): Figure out if we need this. 158 // TODO(abarth): Figure out if we need this.
167 #define MESSAGE_PUMP_UI NULL 159 #define MESSAGE_PUMP_UI NULL
168 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and 160 // ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and
169 // doesn't require extra support for watching file descriptors. 161 // doesn't require extra support for watching file descriptors.
170 #define MESSAGE_PUMP_IO new MessagePumpDefault(); 162 #define MESSAGE_PUMP_IO new MessagePumpDefault()
171 #elif defined(OS_POSIX) // POSIX but not MACOSX. 163 #elif defined(OS_POSIX) // POSIX but not MACOSX.
172 #define MESSAGE_PUMP_UI new MessagePumpForUI() 164 #define MESSAGE_PUMP_UI new MessagePumpForUI()
173 #define MESSAGE_PUMP_IO new MessagePumpLibevent() 165 #define MESSAGE_PUMP_IO new MessagePumpLibevent()
174 #else 166 #else
175 #error Not implemented 167 #error Not implemented
176 #endif 168 #endif
177 169
178 if (type_ == TYPE_UI) { 170 if (type_ == TYPE_UI) {
179 if (message_pump_for_ui_factory_) 171 if (message_pump_for_ui_factory_)
180 pump_ = message_pump_for_ui_factory_(); 172 pump_.reset(message_pump_for_ui_factory_());
181 else 173 else
182 pump_ = MESSAGE_PUMP_UI; 174 pump_.reset(MESSAGE_PUMP_UI);
183 } else if (type_ == TYPE_IO) { 175 } else if (type_ == TYPE_IO) {
184 pump_ = MESSAGE_PUMP_IO; 176 pump_.reset(MESSAGE_PUMP_IO);
185 } else { 177 } else {
186 DCHECK_EQ(TYPE_DEFAULT, type_); 178 DCHECK_EQ(TYPE_DEFAULT, type_);
187 pump_ = new MessagePumpDefault(); 179 pump_.reset(new MessagePumpDefault());
188 } 180 }
189 } 181 }
190 182
191 MessageLoop::~MessageLoop() { 183 MessageLoop::~MessageLoop() {
192 DCHECK_EQ(this, current()); 184 DCHECK_EQ(this, current());
193 185
194 DCHECK(!run_loop_); 186 DCHECK(!run_loop_);
195 187
196 // Clean up any unprocessed tasks, but take care: deleting a task could 188 // Clean up any unprocessed tasks, but take care: deleting a task could
197 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 189 // result in the addition of more tasks (e.g., via DeleteSoon). We set a
(...skipping 11 matching lines...) Expand all
209 break; 201 break;
210 } 202 }
211 DCHECK(!did_work); 203 DCHECK(!did_work);
212 204
213 // Let interested parties have one last shot at accessing this. 205 // Let interested parties have one last shot at accessing this.
214 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 206 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
215 WillDestroyCurrentMessageLoop()); 207 WillDestroyCurrentMessageLoop());
216 208
217 thread_task_runner_handle_.reset(); 209 thread_task_runner_handle_.reset();
218 210
219 // Tell the message_loop_proxy that we are dying. 211 // Tell the incoming queue that we are dying.
220 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> 212 incoming_task_queue_->WillDestroyCurrentMessageLoop();
221 WillDestroyCurrentMessageLoop(); 213 incoming_task_queue_ = NULL;
222 message_loop_proxy_ = NULL; 214 message_loop_proxy_ = NULL;
223 215
224 // OK, now make it so that no one can find us. 216 // OK, now make it so that no one can find us.
225 lazy_tls_ptr.Pointer()->Set(NULL); 217 lazy_tls_ptr.Pointer()->Set(NULL);
226
227 #if defined(OS_WIN)
228 // If we left the high-resolution timer activated, deactivate it now.
229 // Doing this is not-critical, it is mainly to make sure we track
230 // the high resolution timer activations properly in our unit tests.
231 if (!high_resolution_timer_expiration_.is_null()) {
232 Time::ActivateHighResolutionTimer(false);
233 high_resolution_timer_expiration_ = TimeTicks();
234 }
235 #endif
236 } 218 }
237 219
238 // static 220 // static
239 MessageLoop* MessageLoop::current() { 221 MessageLoop* MessageLoop::current() {
240 // TODO(darin): sadly, we cannot enable this yet since people call us even 222 // TODO(darin): sadly, we cannot enable this yet since people call us even
241 // when they have no intention of using us. 223 // when they have no intention of using us.
242 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; 224 // DCHECK(loop) << "Ouch, did you forget to initialize me?";
243 return lazy_tls_ptr.Pointer()->Get(); 225 return lazy_tls_ptr.Pointer()->Get();
244 } 226 }
245 227
(...skipping 20 matching lines...) Expand all
266 void MessageLoop::RemoveDestructionObserver( 248 void MessageLoop::RemoveDestructionObserver(
267 DestructionObserver* destruction_observer) { 249 DestructionObserver* destruction_observer) {
268 DCHECK_EQ(this, current()); 250 DCHECK_EQ(this, current());
269 destruction_observers_.RemoveObserver(destruction_observer); 251 destruction_observers_.RemoveObserver(destruction_observer);
270 } 252 }
271 253
272 void MessageLoop::PostTask( 254 void MessageLoop::PostTask(
273 const tracked_objects::Location& from_here, 255 const tracked_objects::Location& from_here,
274 const Closure& task) { 256 const Closure& task) {
275 DCHECK(!task.is_null()) << from_here.ToString(); 257 DCHECK(!task.is_null()) << from_here.ToString();
276 PendingTask pending_task( 258 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true);
277 from_here, task, CalculateDelayedRuntime(TimeDelta()), true);
278 AddToIncomingQueue(&pending_task, false);
279 } 259 }
280 260
281 bool MessageLoop::TryPostTask( 261 bool MessageLoop::TryPostTask(
282 const tracked_objects::Location& from_here, 262 const tracked_objects::Location& from_here,
283 const Closure& task) { 263 const Closure& task) {
284 DCHECK(!task.is_null()) << from_here.ToString(); 264 DCHECK(!task.is_null()) << from_here.ToString();
285 PendingTask pending_task( 265 return incoming_task_queue_->TryAddToIncomingQueue(from_here, task);
286 from_here, task, CalculateDelayedRuntime(TimeDelta()), true);
287 return AddToIncomingQueue(&pending_task, true);
288 } 266 }
289 267
290 void MessageLoop::PostDelayedTask( 268 void MessageLoop::PostDelayedTask(
291 const tracked_objects::Location& from_here, 269 const tracked_objects::Location& from_here,
292 const Closure& task, 270 const Closure& task,
293 TimeDelta delay) { 271 TimeDelta delay) {
294 DCHECK(!task.is_null()) << from_here.ToString(); 272 DCHECK(!task.is_null()) << from_here.ToString();
295 PendingTask pending_task( 273 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true);
296 from_here, task, CalculateDelayedRuntime(delay), true);
297 AddToIncomingQueue(&pending_task, false);
298 } 274 }
299 275
300 void MessageLoop::PostNonNestableTask( 276 void MessageLoop::PostNonNestableTask(
301 const tracked_objects::Location& from_here, 277 const tracked_objects::Location& from_here,
302 const Closure& task) { 278 const Closure& task) {
303 DCHECK(!task.is_null()) << from_here.ToString(); 279 DCHECK(!task.is_null()) << from_here.ToString();
304 PendingTask pending_task( 280 incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false);
305 from_here, task, CalculateDelayedRuntime(TimeDelta()), false);
306 AddToIncomingQueue(&pending_task, false);
307 } 281 }
308 282
309 void MessageLoop::PostNonNestableDelayedTask( 283 void MessageLoop::PostNonNestableDelayedTask(
310 const tracked_objects::Location& from_here, 284 const tracked_objects::Location& from_here,
311 const Closure& task, 285 const Closure& task,
312 TimeDelta delay) { 286 TimeDelta delay) {
313 DCHECK(!task.is_null()) << from_here.ToString(); 287 DCHECK(!task.is_null()) << from_here.ToString();
314 PendingTask pending_task( 288 incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false);
315 from_here, task, CalculateDelayedRuntime(delay), false);
316 AddToIncomingQueue(&pending_task, false);
317 } 289 }
318 290
319 void MessageLoop::Run() { 291 void MessageLoop::Run() {
320 RunLoop run_loop; 292 RunLoop run_loop;
321 run_loop.Run(); 293 run_loop.Run();
322 } 294 }
323 295
324 void MessageLoop::RunUntilIdle() { 296 void MessageLoop::RunUntilIdle() {
325 RunLoop run_loop; 297 RunLoop run_loop;
326 run_loop.RunUntilIdle(); 298 run_loop.RunUntilIdle();
(...skipping 29 matching lines...) Expand all
356 Closure MessageLoop::QuitWhenIdleClosure() { 328 Closure MessageLoop::QuitWhenIdleClosure() {
357 return Bind(&QuitCurrentWhenIdle); 329 return Bind(&QuitCurrentWhenIdle);
358 } 330 }
359 331
360 void MessageLoop::SetNestableTasksAllowed(bool allowed) { 332 void MessageLoop::SetNestableTasksAllowed(bool allowed) {
361 if (nestable_tasks_allowed_ != allowed) { 333 if (nestable_tasks_allowed_ != allowed) {
362 nestable_tasks_allowed_ = allowed; 334 nestable_tasks_allowed_ = allowed;
363 if (!nestable_tasks_allowed_) 335 if (!nestable_tasks_allowed_)
364 return; 336 return;
365 // Start the native pump if we are not already pumping. 337 // Start the native pump if we are not already pumping.
366 pump_->ScheduleWork(); 338 WakeUpPump();
367 } 339 }
368 } 340 }
369 341
370 bool MessageLoop::NestableTasksAllowed() const { 342 bool MessageLoop::NestableTasksAllowed() const {
371 return nestable_tasks_allowed_; 343 return nestable_tasks_allowed_;
372 } 344 }
373 345
374 bool MessageLoop::IsNested() { 346 bool MessageLoop::IsNested() {
375 return run_loop_->run_depth_ > 1; 347 return run_loop_->run_depth_ > 1;
376 } 348 }
377 349
378 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { 350 void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
379 DCHECK_EQ(this, current()); 351 DCHECK_EQ(this, current());
380 task_observers_.AddObserver(task_observer); 352 task_observers_.AddObserver(task_observer);
381 } 353 }
382 354
383 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { 355 void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
384 DCHECK_EQ(this, current()); 356 DCHECK_EQ(this, current());
385 task_observers_.RemoveObserver(task_observer); 357 task_observers_.RemoveObserver(task_observer);
386 } 358 }
387 359
388 void MessageLoop::AssertIdle() const {
389 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|.
390 AutoLock lock(incoming_queue_lock_);
391 DCHECK(incoming_queue_.empty());
392 }
393
394 bool MessageLoop::is_running() const { 360 bool MessageLoop::is_running() const {
395 DCHECK_EQ(this, current()); 361 DCHECK_EQ(this, current());
396 return run_loop_ != NULL; 362 return run_loop_ != NULL;
397 } 363 }
398 364
365 bool MessageLoop::IsHighResolutionTimerEnabledForTest() {
366 return incoming_task_queue_->IsHighResolutionTimerEnabledForTest();
367 }
368
369 bool MessageLoop::IsIdleForTest() {
370 // We only check the imcoming queue|, since we don't want to lock the work
371 // queue.
372 return incoming_task_queue_->IsIdleForTest();
373 }
374
375 void MessageLoop::LockWaitUnLockForTest(WaitableEvent* caller_wait,
376 WaitableEvent* caller_signal) {
377 incoming_task_queue_->LockWaitUnLockForTest(caller_wait, caller_signal);
378 }
379
399 //------------------------------------------------------------------------------ 380 //------------------------------------------------------------------------------
400 381
401 // Runs the loop in two different SEH modes: 382 // Runs the loop in two different SEH modes:
402 // enable_SEH_restoration_ = false : any unhandled exception goes to the last 383 // enable_SEH_restoration_ = false : any unhandled exception goes to the last
403 // one that calls SetUnhandledExceptionFilter(). 384 // one that calls SetUnhandledExceptionFilter().
404 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter 385 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter
405 // that was existed before the loop was run. 386 // that was existed before the loop was run.
406 void MessageLoop::RunHandler() { 387 void MessageLoop::RunHandler() {
407 #if defined(OS_WIN) 388 #if defined(OS_WIN)
408 if (exception_restoration_) { 389 if (exception_restoration_) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 434
454 RunTask(pending_task); 435 RunTask(pending_task);
455 return true; 436 return true;
456 } 437 }
457 438
458 void MessageLoop::RunTask(const PendingTask& pending_task) { 439 void MessageLoop::RunTask(const PendingTask& pending_task) {
459 tracked_objects::TrackedTime start_time = 440 tracked_objects::TrackedTime start_time =
460 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); 441 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally);
461 442
462 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", 443 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask",
463 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)), 444 TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
464 "queue_duration", 445 "queue_duration",
465 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); 446 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds());
466 TRACE_EVENT2("task", "MessageLoop::RunTask", 447 TRACE_EVENT2("task", "MessageLoop::RunTask",
467 "src_file", pending_task.posted_from.file_name(), 448 "src_file", pending_task.posted_from.file_name(),
468 "src_func", pending_task.posted_from.function_name()); 449 "src_func", pending_task.posted_from.function_name());
469 450
470 DCHECK(nestable_tasks_allowed_); 451 DCHECK(nestable_tasks_allowed_);
471 // Execute the task and assume the worst: It is probably not reentrant. 452 // Execute the task and assume the worst: It is probably not reentrant.
472 nestable_tasks_allowed_ = false; 453 nestable_tasks_allowed_ = false;
473 454
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 // and the task isn't nestable. 487 // and the task isn't nestable.
507 deferred_non_nestable_work_queue_.push(pending_task); 488 deferred_non_nestable_work_queue_.push(pending_task);
508 return false; 489 return false;
509 } 490 }
510 491
511 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 492 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
512 // Move to the delayed work queue. 493 // Move to the delayed work queue.
513 delayed_work_queue_.push(pending_task); 494 delayed_work_queue_.push(pending_task);
514 } 495 }
515 496
516 void MessageLoop::ReloadWorkQueue() {
517 // We can improve performance of our loading tasks from incoming_queue_ to
518 // work_queue_ by waiting until the last minute (work_queue_ is empty) to
519 // load. That reduces the number of locks-per-task significantly when our
520 // queues get large.
521 if (!work_queue_.empty())
522 return; // Wait till we *really* need to lock and load.
523
524 // Acquire all we can from the inter-thread queue with one lock acquisition.
525 {
526 AutoLock lock(incoming_queue_lock_);
527 if (incoming_queue_.empty())
528 return;
529 incoming_queue_.Swap(&work_queue_); // Constant time
530 DCHECK(incoming_queue_.empty());
531 }
532 }
533
534 bool MessageLoop::DeletePendingTasks() { 497 bool MessageLoop::DeletePendingTasks() {
535 bool did_work = !work_queue_.empty(); 498 bool did_work = !work_queue_.empty();
536 while (!work_queue_.empty()) { 499 while (!work_queue_.empty()) {
537 PendingTask pending_task = work_queue_.front(); 500 PendingTask pending_task = work_queue_.front();
538 work_queue_.pop(); 501 work_queue_.pop();
539 if (!pending_task.delayed_run_time.is_null()) { 502 if (!pending_task.delayed_run_time.is_null()) {
540 // We want to delete delayed tasks in the same order in which they would 503 // We want to delete delayed tasks in the same order in which they would
541 // normally be deleted in case of any funny dependencies between delayed 504 // normally be deleted in case of any funny dependencies between delayed
542 // tasks. 505 // tasks.
543 AddToDelayedWorkQueue(pending_task); 506 AddToDelayedWorkQueue(pending_task);
544 } 507 }
545 } 508 }
546 did_work |= !deferred_non_nestable_work_queue_.empty(); 509 did_work |= !deferred_non_nestable_work_queue_.empty();
547 while (!deferred_non_nestable_work_queue_.empty()) { 510 while (!deferred_non_nestable_work_queue_.empty()) {
548 deferred_non_nestable_work_queue_.pop(); 511 deferred_non_nestable_work_queue_.pop();
549 } 512 }
550 did_work |= !delayed_work_queue_.empty(); 513 did_work |= !delayed_work_queue_.empty();
551 514
552 // Historically, we always delete the task regardless of valgrind status. It's 515 // Historically, we always delete the task regardless of valgrind status. It's
553 // not completely clear why we want to leak them in the loops above. This 516 // not completely clear why we want to leak them in the loops above. This
554 // code is replicating legacy behavior, and should not be considered 517 // code is replicating legacy behavior, and should not be considered
555 // absolutely "correct" behavior. See TODO above about deleting all tasks 518 // absolutely "correct" behavior. See TODO above about deleting all tasks
556 // when it's safe. 519 // when it's safe.
557 while (!delayed_work_queue_.empty()) { 520 while (!delayed_work_queue_.empty()) {
558 delayed_work_queue_.pop(); 521 delayed_work_queue_.pop();
559 } 522 }
560 return did_work; 523 return did_work;
561 } 524 }
562 525
563 TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { 526 uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) {
564 TimeTicks delayed_run_time; 527 return (static_cast<uint64>(task.sequence_num) << 32) |
565 if (delay > TimeDelta()) { 528 static_cast<uint64>(reinterpret_cast<intptr_t>(this));
566 delayed_run_time = TimeTicks::Now() + delay;
567
568 #if defined(OS_WIN)
569 if (high_resolution_timer_expiration_.is_null()) {
570 // Windows timers are granular to 15.6ms. If we only set high-res
571 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms,
572 // which as a percentage is pretty inaccurate. So enable high
573 // res timers for any timer which is within 2x of the granularity.
574 // This is a tradeoff between accuracy and power management.
575 bool needs_high_res_timers = delay.InMilliseconds() <
576 (2 * Time::kMinLowResolutionThresholdMs);
577 if (needs_high_res_timers) {
578 if (Time::ActivateHighResolutionTimer(true)) {
579 high_resolution_timer_expiration_ = TimeTicks::Now() +
580 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs);
581 }
582 }
583 }
584 #endif
585 } else {
586 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
587 }
588
589 #if defined(OS_WIN)
590 if (!high_resolution_timer_expiration_.is_null()) {
591 if (TimeTicks::Now() > high_resolution_timer_expiration_) {
592 Time::ActivateHighResolutionTimer(false);
593 high_resolution_timer_expiration_ = TimeTicks();
594 }
595 }
596 #endif
597
598 return delayed_run_time;
599 } 529 }
600 530
601 // Possibly called on a background thread! 531 void MessageLoop::ReloadWorkQueue() {
602 bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, 532 // We can improve performance of our loading tasks from the incoming queue to
603 bool use_try_lock) { 533 // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to
604 // Warning: Don't try to short-circuit, and handle this thread's tasks more 534 // load. That reduces the number of locks-per-task significantly when our
605 // directly, as it could starve handling of foreign threads. Put every task 535 // queues get large.
606 // into this queue. 536 if (work_queue_.empty())
537 incoming_task_queue_->ReloadWorkQueue(&work_queue_);
538 }
607 539
608 scoped_refptr<MessagePump> pump; 540 void MessageLoop::WakeUpPump() {
609 { 541 pump_->ScheduleWork();
610 if (use_try_lock) {
611 if (!incoming_queue_lock_.Try()) {
612 pending_task->task.Reset();
613 return false;
614 }
615 } else {
616 incoming_queue_lock_.Acquire();
617 }
618 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired());
619 // Initialize the sequence number. The sequence number is used for delayed
620 // tasks (to faciliate FIFO sorting when two tasks have the same
621 // delayed_run_time value) and for identifying the task in about:tracing.
622 pending_task->sequence_num = next_sequence_num_++;
623
624 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask",
625 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this)));
626
627 bool was_empty = incoming_queue_.empty();
628 incoming_queue_.push(*pending_task);
629 pending_task->task.Reset();
630 if (!was_empty)
631 return true; // Someone else should have started the sub-pump.
632
633 pump = pump_;
634 }
635 // Since the incoming_queue_ may contain a task that destroys this message
636 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
637 // We use a stack-based reference to the message pump so that we can call
638 // ScheduleWork outside of incoming_queue_lock_.
639
640 pump->ScheduleWork();
641 return true;
642 } 542 }
643 543
644 //------------------------------------------------------------------------------ 544 //------------------------------------------------------------------------------
645 // Method and data for histogramming events and actions taken by each instance 545 // Method and data for histogramming events and actions taken by each instance
646 // on each thread. 546 // on each thread.
647 547
648 void MessageLoop::StartHistogrammer() { 548 void MessageLoop::StartHistogrammer() {
649 #if !defined(OS_NACL) // NaCl build has no metrics code. 549 #if !defined(OS_NACL) // NaCl build has no metrics code.
650 if (enable_histogrammer_ && !message_histogram_ 550 if (enable_histogrammer_ && !message_histogram_
651 && StatisticsRecorder::IsActive()) { 551 && StatisticsRecorder::IsActive()) {
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after
828 fd, 728 fd,
829 persistent, 729 persistent,
830 mode, 730 mode,
831 controller, 731 controller,
832 delegate); 732 delegate);
833 } 733 }
834 734
835 #endif 735 #endif
836 736
837 } // namespace base 737 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698