message_loop.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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 3// found in the LICENSE file. 4 5#include "base/message_loop/message_loop.h" 6 7#include <algorithm> 8 9#include "base/bind.h" 10#include "base/compiler_specific.h" 11#include "base/debug/alias.h" 12#include "base/debug/trace_event.h" 13#include "base/lazy_instance.h" 14#include "base/logging.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" 18#include "base/metrics/histogram.h" 19#include "base/metrics/statistics_recorder.h" 20#include "base/run_loop.h" 21#include "base/third_party/dynamic_annotations/dynamic_annotations.h" 22#include "base/thread_task_runner_handle.h" 23#include "base/threading/thread_local.h" 24#include "base/time/time.h" 25#include "base/tracked_objects.h" 26 27#if defined(OS_MACOSX) 28#include "base/message_loop/message_pump_mac.h" 29#endif 30#if defined(OS_POSIX) && !defined(OS_IOS) 31#include "base/message_loop/message_pump_libevent.h" 32#endif 33#if defined(OS_ANDROID) 34#include "base/message_loop/message_pump_android.h" 35#endif 36 37#if defined(TOOLKIT_GTK) 38#include <gdk/gdk.h> 39#include <gdk/gdkx.h> 40#endif 41 42namespace base { 43 44namespace { 45 46// A lazily created thread local storage for quick access to a thread's message 47// loop, if one exists. This should be safe and free of static constructors. 48LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr = 49 LAZY_INSTANCE_INITIALIZER; 50 51// Logical events for Histogram profiling. Run with -message-loop-histogrammer 52// to get an accounting of messages and actions taken on each thread. 53const int kTaskRunEvent = 0x1; 54const int kTimerEvent = 0x2; 55 56// Provide range of message IDs for use in histogramming and debug display. 57const int kLeastNonZeroMessageId = 1; 58const int kMaxMessageId = 1099; 59const int kNumberOfDistinctMessagesDisplayed = 1100; 60 61// Provide a macro that takes an expression (such as a constant, or macro 62// constant) and creates a pair to initalize an array of pairs. In this case, 63// our pair consists of the expressions value, and the "stringized" version 64// of the expression (i.e., the exrpression put in quotes). For example, if 65// we have: 66// #define FOO 2 67// #define BAR 5 68// then the following: 69// VALUE_TO_NUMBER_AND_NAME(FOO + BAR) 70// will expand to: 71// {7, "FOO + BAR"} 72// We use the resulting array as an argument to our histogram, which reads the 73// number as a bucket identifier, and proceeds to use the corresponding name 74// in the pair (i.e., the quoted string) when printing out a histogram. 75#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name}, 76 77const LinearHistogram::DescriptionPair event_descriptions_[] = { 78 // Provide some pretty print capability in our histogram for our internal 79 // messages. 80 81 // A few events we handle (kindred to messages), and used to profile actions. 82 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) 83 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) 84 85 {-1, NULL} // The list must be null terminated, per API to histogram. 86}; 87 88bool enable_histogrammer_ = false; 89 90MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL; 91 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. 95uint64 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// Returns true if MessagePump::ScheduleWork() must be called one 101// time for every task that is added to the MessageLoop incoming queue. 102bool AlwaysNotifyPump(MessageLoop::Type type) { 103#if defined(OS_ANDROID) 104 return type == MessageLoop::TYPE_UI; 105#else 106 return false; 107#endif 108} 109 110} // namespace 111 112//------------------------------------------------------------------------------ 113 114#if defined(OS_WIN) 115 116// Upon a SEH exception in this thread, it restores the original unhandled 117// exception filter. 118static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { 119 ::SetUnhandledExceptionFilter(old_filter); 120 return EXCEPTION_CONTINUE_SEARCH; 121} 122 123// Retrieves a pointer to the current unhandled exception filter. There 124// is no standalone getter method. 125static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { 126 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; 127 top_filter = ::SetUnhandledExceptionFilter(0); 128 ::SetUnhandledExceptionFilter(top_filter); 129 return top_filter; 130} 131 132#endif // defined(OS_WIN) 133 134//------------------------------------------------------------------------------ 135 136MessageLoop::TaskObserver::TaskObserver() { 137} 138 139MessageLoop::TaskObserver::~TaskObserver() { 140} 141 142MessageLoop::DestructionObserver::~DestructionObserver() { 143} 144 145//------------------------------------------------------------------------------ 146 147MessageLoop::MessageLoop(Type type) 148 : type_(type), 149 nestable_tasks_allowed_(true), 150 exception_restoration_(false), 151 message_histogram_(NULL), 152 run_loop_(NULL), 153#if defined(OS_WIN) 154 os_modal_loop_(false), 155#endif // OS_WIN 156 next_sequence_num_(0) { 157 DCHECK(!current()) << "should only have one message loop per thread"; 158 lazy_tls_ptr.Pointer()->Set(this); 159 160 message_loop_proxy_ = new MessageLoopProxyImpl(); 161 thread_task_runner_handle_.reset( 162 new ThreadTaskRunnerHandle(message_loop_proxy_)); 163 164// TODO(rvargas): Get rid of the OS guards. 165#if defined(OS_WIN) 166#define MESSAGE_PUMP_UI new MessagePumpForUI() 167#define MESSAGE_PUMP_IO new MessagePumpForIO() 168#elif defined(OS_IOS) 169#define MESSAGE_PUMP_UI MessagePumpMac::Create() 170#define MESSAGE_PUMP_IO new MessagePumpIOSForIO() 171#elif defined(OS_MACOSX) 172#define MESSAGE_PUMP_UI MessagePumpMac::Create() 173#define MESSAGE_PUMP_IO new MessagePumpLibevent() 174#elif defined(OS_NACL) 175// Currently NaCl doesn't have a UI MessageLoop. 176// TODO(abarth): Figure out if we need this. 177#define MESSAGE_PUMP_UI NULL 178// ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and 179// doesn't require extra support for watching file descriptors. 180#define MESSAGE_PUMP_IO new MessagePumpDefault(); 181#elif defined(OS_POSIX) // POSIX but not MACOSX. 182#define MESSAGE_PUMP_UI new MessagePumpForUI() 183#define MESSAGE_PUMP_IO new MessagePumpLibevent() 184#else 185#error Not implemented 186#endif 187 188 if (type_ == TYPE_UI) { 189 if (message_pump_for_ui_factory_) 190 pump_ = message_pump_for_ui_factory_(); 191 else 192 pump_ = MESSAGE_PUMP_UI; 193 } else if (type_ == TYPE_IO) { 194 pump_ = MESSAGE_PUMP_IO; 195 } else { 196 DCHECK_EQ(TYPE_DEFAULT, type_); 197 pump_ = new MessagePumpDefault(); 198 } 199} 200 201MessageLoop::~MessageLoop() { 202 DCHECK_EQ(this, current()); 203 204 DCHECK(!run_loop_); 205 206 // Clean up any unprocessed tasks, but take care: deleting a task could 207 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 208 // limit on the number of times we will allow a deleted task to generate more 209 // tasks. Normally, we should only pass through this loop once or twice. If 210 // we end up hitting the loop limit, then it is probably due to one task that 211 // is being stubborn. Inspect the queues to see who is left. 212 bool did_work; 213 for (int i = 0; i < 100; ++i) { 214 DeletePendingTasks(); 215 ReloadWorkQueue(); 216 // If we end up with empty queues, then break out of the loop. 217 did_work = DeletePendingTasks(); 218 if (!did_work) 219 break; 220 } 221 DCHECK(!did_work); 222 223 // Let interested parties have one last shot at accessing this. 224 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 225 WillDestroyCurrentMessageLoop()); 226 227 thread_task_runner_handle_.reset(); 228 229 // Tell the message_loop_proxy that we are dying. 230 static_cast<MessageLoopProxyImpl*>(message_loop_proxy_.get())-> 231 WillDestroyCurrentMessageLoop(); 232 message_loop_proxy_ = NULL; 233 234 // OK, now make it so that no one can find us. 235 lazy_tls_ptr.Pointer()->Set(NULL); 236 237#if defined(OS_WIN) 238 // If we left the high-resolution timer activated, deactivate it now. 239 // Doing this is not-critical, it is mainly to make sure we track 240 // the high resolution timer activations properly in our unit tests. 241 if (!high_resolution_timer_expiration_.is_null()) { 242 Time::ActivateHighResolutionTimer(false); 243 high_resolution_timer_expiration_ = TimeTicks(); 244 } 245#endif 246} 247 248// static 249MessageLoop* MessageLoop::current() { 250 // TODO(darin): sadly, we cannot enable this yet since people call us even 251 // when they have no intention of using us. 252 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; 253 return lazy_tls_ptr.Pointer()->Get(); 254} 255 256// static 257void MessageLoop::EnableHistogrammer(bool enable) { 258 enable_histogrammer_ = enable; 259} 260 261// static 262bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) { 263 if (message_pump_for_ui_factory_) 264 return false; 265 266 message_pump_for_ui_factory_ = factory; 267 return true; 268} 269 270void MessageLoop::AddDestructionObserver( 271 DestructionObserver* destruction_observer) { 272 DCHECK_EQ(this, current()); 273 destruction_observers_.AddObserver(destruction_observer); 274} 275 276void MessageLoop::RemoveDestructionObserver( 277 DestructionObserver* destruction_observer) { 278 DCHECK_EQ(this, current()); 279 destruction_observers_.RemoveObserver(destruction_observer); 280} 281 282void MessageLoop::PostTask( 283 const tracked_objects::Location& from_here, 284 const Closure& task) { 285 DCHECK(!task.is_null()) << from_here.ToString(); 286 PendingTask pending_task( 287 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); 288 AddToIncomingQueue(&pending_task, false); 289} 290 291bool MessageLoop::TryPostTask( 292 const tracked_objects::Location& from_here, 293 const Closure& task) { 294 DCHECK(!task.is_null()) << from_here.ToString(); 295 PendingTask pending_task( 296 from_here, task, CalculateDelayedRuntime(TimeDelta()), true); 297 return AddToIncomingQueue(&pending_task, true); 298} 299 300void MessageLoop::PostDelayedTask( 301 const tracked_objects::Location& from_here, 302 const Closure& task, 303 TimeDelta delay) { 304 DCHECK(!task.is_null()) << from_here.ToString(); 305 PendingTask pending_task( 306 from_here, task, CalculateDelayedRuntime(delay), true); 307 AddToIncomingQueue(&pending_task, false); 308} 309 310void MessageLoop::PostNonNestableTask( 311 const tracked_objects::Location& from_here, 312 const Closure& task) { 313 DCHECK(!task.is_null()) << from_here.ToString(); 314 PendingTask pending_task( 315 from_here, task, CalculateDelayedRuntime(TimeDelta()), false); 316 AddToIncomingQueue(&pending_task, false); 317} 318 319void MessageLoop::PostNonNestableDelayedTask( 320 const tracked_objects::Location& from_here, 321 const Closure& task, 322 TimeDelta delay) { 323 DCHECK(!task.is_null()) << from_here.ToString(); 324 PendingTask pending_task( 325 from_here, task, CalculateDelayedRuntime(delay), false); 326 AddToIncomingQueue(&pending_task, false); 327} 328 329void MessageLoop::Run() { 330 RunLoop run_loop; 331 run_loop.Run(); 332} 333 334void MessageLoop::RunUntilIdle() { 335 RunLoop run_loop; 336 run_loop.RunUntilIdle(); 337} 338 339void MessageLoop::QuitWhenIdle() { 340 DCHECK_EQ(this, current()); 341 if (run_loop_) { 342 run_loop_->quit_when_idle_received_ = true; 343 } else { 344 NOTREACHED() << "Must be inside Run to call Quit"; 345 } 346} 347 348void MessageLoop::QuitNow() { 349 DCHECK_EQ(this, current()); 350 if (run_loop_) { 351 pump_->Quit(); 352 } else { 353 NOTREACHED() << "Must be inside Run to call Quit"; 354 } 355} 356 357bool MessageLoop::IsType(Type type) const { 358 return type_ == type; 359} 360 361static void QuitCurrentWhenIdle() { 362 MessageLoop::current()->QuitWhenIdle(); 363} 364 365// static 366Closure MessageLoop::QuitWhenIdleClosure() { 367 return Bind(&QuitCurrentWhenIdle); 368} 369 370void MessageLoop::SetNestableTasksAllowed(bool allowed) { 371 if (nestable_tasks_allowed_ != allowed) { 372 nestable_tasks_allowed_ = allowed; 373 if (!nestable_tasks_allowed_) 374 return; 375 // Start the native pump if we are not already pumping. 376 pump_->ScheduleWork(); 377 } 378} 379 380bool MessageLoop::NestableTasksAllowed() const { 381 return nestable_tasks_allowed_; 382} 383 384bool MessageLoop::IsNested() { 385 return run_loop_->run_depth_ > 1; 386} 387 388void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { 389 DCHECK_EQ(this, current()); 390 task_observers_.AddObserver(task_observer); 391} 392 393void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { 394 DCHECK_EQ(this, current()); 395 task_observers_.RemoveObserver(task_observer); 396} 397 398void MessageLoop::AssertIdle() const { 399 // We only check |incoming_queue_|, since we don't want to lock |work_queue_|. 400 AutoLock lock(incoming_queue_lock_); 401 DCHECK(incoming_queue_.empty()); 402} 403 404bool MessageLoop::is_running() const { 405 DCHECK_EQ(this, current()); 406 return run_loop_ != NULL; 407} 408 409//------------------------------------------------------------------------------ 410 411// Runs the loop in two different SEH modes: 412// enable_SEH_restoration_ = false : any unhandled exception goes to the last 413// one that calls SetUnhandledExceptionFilter(). 414// enable_SEH_restoration_ = true : any unhandled exception goes to the filter 415// that was existed before the loop was run. 416void MessageLoop::RunHandler() { 417#if defined(OS_WIN) 418 if (exception_restoration_) { 419 RunInternalInSEHFrame(); 420 return; 421 } 422#endif 423 424 RunInternal(); 425} 426 427#if defined(OS_WIN) 428__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() { 429 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); 430 __try { 431 RunInternal(); 432 } __except(SEHFilter(current_filter)) { 433 } 434 return; 435} 436#endif 437 438void MessageLoop::RunInternal() { 439 DCHECK_EQ(this, current()); 440 441 StartHistogrammer(); 442 443#if !defined(OS_MACOSX) && !defined(OS_ANDROID) 444 if (run_loop_->dispatcher_ && type() == TYPE_UI) { 445 static_cast<MessagePumpForUI*>(pump_.get())-> 446 RunWithDispatcher(this, run_loop_->dispatcher_); 447 return; 448 } 449#endif 450 451 pump_->Run(this); 452} 453 454bool MessageLoop::ProcessNextDelayedNonNestableTask() { 455 if (run_loop_->run_depth_ != 1) 456 return false; 457 458 if (deferred_non_nestable_work_queue_.empty()) 459 return false; 460 461 PendingTask pending_task = deferred_non_nestable_work_queue_.front(); 462 deferred_non_nestable_work_queue_.pop(); 463 464 RunTask(pending_task); 465 return true; 466} 467 468void MessageLoop::RunTask(const PendingTask& pending_task) { 469 tracked_objects::TrackedTime start_time = 470 tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally); 471 472 TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask", 473 TRACE_ID_MANGLE(GetTaskTraceID(pending_task, this)), 474 "queue_duration", 475 (start_time - pending_task.EffectiveTimePosted()).InMilliseconds()); 476 TRACE_EVENT2("task", "MessageLoop::RunTask", 477 "src_file", pending_task.posted_from.file_name(), 478 "src_func", pending_task.posted_from.function_name()); 479 480 DCHECK(nestable_tasks_allowed_); 481 // Execute the task and assume the worst: It is probably not reentrant. 482 nestable_tasks_allowed_ = false; 483 484 // Before running the task, store the program counter where it was posted 485 // and deliberately alias it to ensure it is on the stack if the task 486 // crashes. Be careful not to assume that the variable itself will have the 487 // expected value when displayed by the optimizer in an optimized build. 488 // Look at a memory dump of the stack. 489 const void* program_counter = 490 pending_task.posted_from.program_counter(); 491 debug::Alias(&program_counter); 492 493 HistogramEvent(kTaskRunEvent); 494 495 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 496 WillProcessTask(pending_task)); 497 pending_task.task.Run(); 498 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 499 DidProcessTask(pending_task)); 500 501 tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, 502 start_time, tracked_objects::ThreadData::NowForEndOfRun()); 503 504 nestable_tasks_allowed_ = true; 505} 506 507bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { 508 if (pending_task.nestable || run_loop_->run_depth_ == 1) { 509 RunTask(pending_task); 510 // Show that we ran a task (Note: a new one might arrive as a 511 // consequence!). 512 return true; 513 } 514 515 // We couldn't run the task now because we're in a nested message loop 516 // and the task isn't nestable. 517 deferred_non_nestable_work_queue_.push(pending_task); 518 return false; 519} 520 521void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 522 // Move to the delayed work queue. 523 delayed_work_queue_.push(pending_task); 524} 525 526void MessageLoop::ReloadWorkQueue() { 527 // We can improve performance of our loading tasks from incoming_queue_ to 528 // work_queue_ by waiting until the last minute (work_queue_ is empty) to 529 // load. That reduces the number of locks-per-task significantly when our 530 // queues get large. 531 if (!work_queue_.empty()) 532 return; // Wait till we *really* need to lock and load. 533 534 // Acquire all we can from the inter-thread queue with one lock acquisition. 535 { 536 AutoLock lock(incoming_queue_lock_); 537 if (incoming_queue_.empty()) 538 return; 539 incoming_queue_.Swap(&work_queue_); // Constant time 540 DCHECK(incoming_queue_.empty()); 541 } 542} 543 544bool MessageLoop::DeletePendingTasks() { 545 bool did_work = !work_queue_.empty(); 546 while (!work_queue_.empty()) { 547 PendingTask pending_task = work_queue_.front(); 548 work_queue_.pop(); 549 if (!pending_task.delayed_run_time.is_null()) { 550 // We want to delete delayed tasks in the same order in which they would 551 // normally be deleted in case of any funny dependencies between delayed 552 // tasks. 553 AddToDelayedWorkQueue(pending_task); 554 } 555 } 556 did_work |= !deferred_non_nestable_work_queue_.empty(); 557 while (!deferred_non_nestable_work_queue_.empty()) { 558 deferred_non_nestable_work_queue_.pop(); 559 } 560 did_work |= !delayed_work_queue_.empty(); 561 562 // Historically, we always delete the task regardless of valgrind status. It's 563 // not completely clear why we want to leak them in the loops above. This 564 // code is replicating legacy behavior, and should not be considered 565 // absolutely "correct" behavior. See TODO above about deleting all tasks 566 // when it's safe. 567 while (!delayed_work_queue_.empty()) { 568 delayed_work_queue_.pop(); 569 } 570 return did_work; 571} 572 573TimeTicks MessageLoop::CalculateDelayedRuntime(TimeDelta delay) { 574 TimeTicks delayed_run_time; 575 if (delay > TimeDelta()) { 576 delayed_run_time = TimeTicks::Now() + delay; 577 578#if defined(OS_WIN) 579 if (high_resolution_timer_expiration_.is_null()) { 580 // Windows timers are granular to 15.6ms. If we only set high-res 581 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, 582 // which as a percentage is pretty inaccurate. So enable high 583 // res timers for any timer which is within 2x of the granularity. 584 // This is a tradeoff between accuracy and power management. 585 bool needs_high_res_timers = delay.InMilliseconds() < 586 (2 * Time::kMinLowResolutionThresholdMs); 587 if (needs_high_res_timers) { 588 if (Time::ActivateHighResolutionTimer(true)) { 589 high_resolution_timer_expiration_ = TimeTicks::Now() + 590 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); 591 } 592 } 593 } 594#endif 595 } else { 596 DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative"; 597 } 598 599#if defined(OS_WIN) 600 if (!high_resolution_timer_expiration_.is_null()) { 601 if (TimeTicks::Now() > high_resolution_timer_expiration_) { 602 Time::ActivateHighResolutionTimer(false); 603 high_resolution_timer_expiration_ = TimeTicks(); 604 } 605 } 606#endif 607 608 return delayed_run_time; 609} 610 611// Possibly called on a background thread! 612bool MessageLoop::AddToIncomingQueue(PendingTask* pending_task, 613 bool use_try_lock) { 614 // Warning: Don't try to short-circuit, and handle this thread's tasks more 615 // directly, as it could starve handling of foreign threads. Put every task 616 // into this queue. 617 618 scoped_refptr<MessagePump> pump; 619 { 620 if (use_try_lock) { 621 if (!incoming_queue_lock_.Try()) { 622 pending_task->task.Reset(); 623 return false; 624 } 625 } else { 626 incoming_queue_lock_.Acquire(); 627 } 628 AutoLock locked(incoming_queue_lock_, AutoLock::AlreadyAcquired()); 629 // Initialize the sequence number. The sequence number is used for delayed 630 // tasks (to faciliate FIFO sorting when two tasks have the same 631 // delayed_run_time value) and for identifying the task in about:tracing. 632 pending_task->sequence_num = next_sequence_num_++; 633 634 TRACE_EVENT_FLOW_BEGIN0("task", "MessageLoop::PostTask", 635 TRACE_ID_MANGLE(GetTaskTraceID(*pending_task, this))); 636 637 bool was_empty = incoming_queue_.empty(); 638 incoming_queue_.push(*pending_task); 639 pending_task->task.Reset(); 640 // The Android UI message loop needs to get notified each time 641 // a task is added to the incoming queue. 642 if (!was_empty && !AlwaysNotifyPump(type_)) 643 return true; // Someone else should have started the sub-pump. 644 645 pump = pump_; 646 } 647 // Since the incoming_queue_ may contain a task that destroys this message 648 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. 649 // We use a stack-based reference to the message pump so that we can call 650 // ScheduleWork outside of incoming_queue_lock_. 651 652 pump->ScheduleWork(); 653 return true; 654} 655 656//------------------------------------------------------------------------------ 657// Method and data for histogramming events and actions taken by each instance 658// on each thread. 659 660void MessageLoop::StartHistogrammer() { 661#if !defined(OS_NACL) // NaCl build has no metrics code. 662 if (enable_histogrammer_ && !message_histogram_ 663 && StatisticsRecorder::IsActive()) { 664 DCHECK(!thread_name_.empty()); 665 message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription( 666 "MsgLoop:" + thread_name_, 667 kLeastNonZeroMessageId, kMaxMessageId, 668 kNumberOfDistinctMessagesDisplayed, 669 message_histogram_->kHexRangePrintingFlag, 670 event_descriptions_); 671 } 672#endif 673} 674 675void MessageLoop::HistogramEvent(int event) { 676#if !defined(OS_NACL) 677 if (message_histogram_) 678 message_histogram_->Add(event); 679#endif 680} 681 682bool MessageLoop::DoWork() { 683 if (!nestable_tasks_allowed_) { 684 // Task can't be executed right now. 685 return false; 686 } 687 688 for (;;) { 689 ReloadWorkQueue(); 690 if (work_queue_.empty()) 691 break; 692 693 // Execute oldest task. 694 do { 695 PendingTask pending_task = work_queue_.front(); 696 work_queue_.pop(); 697 if (!pending_task.delayed_run_time.is_null()) { 698 AddToDelayedWorkQueue(pending_task); 699 // If we changed the topmost task, then it is time to reschedule. 700 if (delayed_work_queue_.top().task.Equals(pending_task.task)) 701 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 702 } else { 703 if (DeferOrRunPendingTask(pending_task)) 704 return true; 705 } 706 } while (!work_queue_.empty()); 707 } 708 709 // Nothing happened. 710 return false; 711} 712 713bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { 714 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 715 recent_time_ = *next_delayed_work_time = TimeTicks(); 716 return false; 717 } 718 719 // When we "fall behind," there will be a lot of tasks in the delayed work 720 // queue that are ready to run. To increase efficiency when we fall behind, 721 // we will only call Time::Now() intermittently, and then process all tasks 722 // that are ready to run before calling it again. As a result, the more we 723 // fall behind (and have a lot of ready-to-run delayed tasks), the more 724 // efficient we'll be at handling the tasks. 725 726 TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time; 727 if (next_run_time > recent_time_) { 728 recent_time_ = TimeTicks::Now(); // Get a better view of Now(); 729 if (next_run_time > recent_time_) { 730 *next_delayed_work_time = next_run_time; 731 return false; 732 } 733 } 734 735 PendingTask pending_task = delayed_work_queue_.top(); 736 delayed_work_queue_.pop(); 737 738 if (!delayed_work_queue_.empty()) 739 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 740 741 return DeferOrRunPendingTask(pending_task); 742} 743 744bool MessageLoop::DoIdleWork() { 745 if (ProcessNextDelayedNonNestableTask()) 746 return true; 747 748 if (run_loop_->quit_when_idle_received_) 749 pump_->Quit(); 750 751 return false; 752} 753 754void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here, 755 void(*deleter)(const void*), 756 const void* object) { 757 PostNonNestableTask(from_here, Bind(deleter, object)); 758} 759 760void MessageLoop::ReleaseSoonInternal( 761 const tracked_objects::Location& from_here, 762 void(*releaser)(const void*), 763 const void* object) { 764 PostNonNestableTask(from_here, Bind(releaser, object)); 765} 766 767//------------------------------------------------------------------------------ 768// MessageLoopForUI 769 770#if defined(OS_WIN) 771void MessageLoopForUI::DidProcessMessage(const MSG& message) { 772 pump_win()->DidProcessMessage(message); 773} 774#endif // defined(OS_WIN) 775 776#if defined(OS_ANDROID) 777void MessageLoopForUI::Start() { 778 // No Histogram support for UI message loop as it is managed by Java side 779 static_cast<MessagePumpForUI*>(pump_.get())->Start(this); 780} 781#endif 782 783#if defined(OS_IOS) 784void MessageLoopForUI::Attach() { 785 static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this); 786} 787#endif 788 789#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) 790void MessageLoopForUI::AddObserver(Observer* observer) { 791 pump_ui()->AddObserver(observer); 792} 793 794void MessageLoopForUI::RemoveObserver(Observer* observer) { 795 pump_ui()->RemoveObserver(observer); 796} 797 798#endif // !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID) 799 800//------------------------------------------------------------------------------ 801// MessageLoopForIO 802 803#if defined(OS_WIN) 804 805void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 806 pump_io()->RegisterIOHandler(file, handler); 807} 808 809bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) { 810 return pump_io()->RegisterJobObject(job, handler); 811} 812 813bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 814 return pump_io()->WaitForIOCompletion(timeout, filter); 815} 816 817#elif defined(OS_IOS) 818 819bool MessageLoopForIO::WatchFileDescriptor(int fd, 820 bool persistent, 821 Mode mode, 822 FileDescriptorWatcher *controller, 823 Watcher *delegate) { 824 return pump_io()->WatchFileDescriptor( 825 fd, 826 persistent, 827 mode, 828 controller, 829 delegate); 830} 831 832#elif defined(OS_POSIX) && !defined(OS_NACL) 833 834bool MessageLoopForIO::WatchFileDescriptor(int fd, 835 bool persistent, 836 Mode mode, 837 FileDescriptorWatcher *controller, 838 Watcher *delegate) { 839 return pump_libevent()->WatchFileDescriptor( 840 fd, 841 persistent, 842 mode, 843 controller, 844 delegate); 845} 846 847#endif 848 849} // namespace base 850