message_loop.cc revision 3345a6884c488ff3a535c2c9acdd33d74b37e311
1// Copyright (c) 2010 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.h" 6 7#include <algorithm> 8 9#include "base/compiler_specific.h" 10#include "base/histogram.h" 11#include "base/lazy_instance.h" 12#include "base/logging.h" 13#include "base/message_pump_default.h" 14#include "base/thread_local.h" 15 16#if defined(OS_MACOSX) 17#include "base/message_pump_mac.h" 18#endif 19#if defined(OS_POSIX) 20#include "base/message_pump_libevent.h" 21#include "base/third_party/valgrind/valgrind.h" 22#endif 23#if defined(OS_POSIX) && !defined(OS_MACOSX) 24#include "base/message_pump_glib.h" 25#endif 26 27using base::Time; 28using base::TimeDelta; 29 30namespace { 31 32// A lazily created thread local storage for quick access to a thread's message 33// loop, if one exists. This should be safe and free of static constructors. 34base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr( 35 base::LINKER_INITIALIZED); 36 37// Logical events for Histogram profiling. Run with -message-loop-histogrammer 38// to get an accounting of messages and actions taken on each thread. 39const int kTaskRunEvent = 0x1; 40const int kTimerEvent = 0x2; 41 42// Provide range of message IDs for use in histogramming and debug display. 43const int kLeastNonZeroMessageId = 1; 44const int kMaxMessageId = 1099; 45const int kNumberOfDistinctMessagesDisplayed = 1100; 46 47// Provide a macro that takes an expression (such as a constant, or macro 48// constant) and creates a pair to initalize an array of pairs. In this case, 49// our pair consists of the expressions value, and the "stringized" version 50// of the expression (i.e., the exrpression put in quotes). For example, if 51// we have: 52// #define FOO 2 53// #define BAR 5 54// then the following: 55// VALUE_TO_NUMBER_AND_NAME(FOO + BAR) 56// will expand to: 57// {7, "FOO + BAR"} 58// We use the resulting array as an argument to our histogram, which reads the 59// number as a bucket identifier, and proceeds to use the corresponding name 60// in the pair (i.e., the quoted string) when printing out a histogram. 61#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name}, 62 63const LinearHistogram::DescriptionPair event_descriptions_[] = { 64 // Provide some pretty print capability in our histogram for our internal 65 // messages. 66 67 // A few events we handle (kindred to messages), and used to profile actions. 68 VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent) 69 VALUE_TO_NUMBER_AND_NAME(kTimerEvent) 70 71 {-1, NULL} // The list must be null terminated, per API to histogram. 72}; 73 74bool enable_histogrammer_ = false; 75 76} // namespace 77 78//------------------------------------------------------------------------------ 79 80#if defined(OS_WIN) 81 82// Upon a SEH exception in this thread, it restores the original unhandled 83// exception filter. 84static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { 85 ::SetUnhandledExceptionFilter(old_filter); 86 return EXCEPTION_CONTINUE_SEARCH; 87} 88 89// Retrieves a pointer to the current unhandled exception filter. There 90// is no standalone getter method. 91static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { 92 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; 93 top_filter = ::SetUnhandledExceptionFilter(0); 94 ::SetUnhandledExceptionFilter(top_filter); 95 return top_filter; 96} 97 98#endif // defined(OS_WIN) 99 100//------------------------------------------------------------------------------ 101 102MessageLoop::TaskObserver::TaskObserver() { 103} 104 105MessageLoop::TaskObserver::~TaskObserver() { 106} 107 108MessageLoop::DestructionObserver::~DestructionObserver() { 109} 110 111//------------------------------------------------------------------------------ 112 113// static 114MessageLoop* MessageLoop::current() { 115 // TODO(darin): sadly, we cannot enable this yet since people call us even 116 // when they have no intention of using us. 117 // DCHECK(loop) << "Ouch, did you forget to initialize me?"; 118 return lazy_tls_ptr.Pointer()->Get(); 119} 120 121MessageLoop::MessageLoop(Type type) 122 : type_(type), 123 nestable_tasks_allowed_(true), 124 exception_restoration_(false), 125 state_(NULL), 126 next_sequence_num_(0) { 127 DCHECK(!current()) << "should only have one message loop per thread"; 128 lazy_tls_ptr.Pointer()->Set(this); 129 130// TODO(rvargas): Get rid of the OS guards. 131#if defined(OS_WIN) 132#define MESSAGE_PUMP_UI new base::MessagePumpForUI() 133#define MESSAGE_PUMP_IO new base::MessagePumpForIO() 134#elif defined(OS_MACOSX) 135#define MESSAGE_PUMP_UI base::MessagePumpMac::Create() 136#define MESSAGE_PUMP_IO new base::MessagePumpLibevent() 137#elif defined(ANDROID) 138#define MESSAGE_PUMP_UI new base::MessagePumpDefault() 139#define MESSAGE_PUMP_IO new base::MessagePumpLibevent() 140#elif defined(OS_POSIX) // POSIX but not MACOSX. 141#define MESSAGE_PUMP_UI new base::MessagePumpForUI() 142#define MESSAGE_PUMP_IO new base::MessagePumpLibevent() 143#else 144#error Not implemented 145#endif 146 147 if (type_ == TYPE_UI) { 148 pump_ = MESSAGE_PUMP_UI; 149 } else if (type_ == TYPE_IO) { 150 pump_ = MESSAGE_PUMP_IO; 151 } else { 152 DCHECK_EQ(TYPE_DEFAULT, type_); 153 pump_ = new base::MessagePumpDefault(); 154 } 155} 156 157MessageLoop::~MessageLoop() { 158 DCHECK(this == current()); 159 160 // Let interested parties have one last shot at accessing this. 161 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 162 WillDestroyCurrentMessageLoop()); 163 164 DCHECK(!state_); 165 166 // Clean up any unprocessed tasks, but take care: deleting a task could 167 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 168 // limit on the number of times we will allow a deleted task to generate more 169 // tasks. Normally, we should only pass through this loop once or twice. If 170 // we end up hitting the loop limit, then it is probably due to one task that 171 // is being stubborn. Inspect the queues to see who is left. 172 bool did_work; 173 for (int i = 0; i < 100; ++i) { 174 DeletePendingTasks(); 175 ReloadWorkQueue(); 176 // If we end up with empty queues, then break out of the loop. 177 did_work = DeletePendingTasks(); 178 if (!did_work) 179 break; 180 } 181 DCHECK(!did_work); 182 183 // OK, now make it so that no one can find us. 184 lazy_tls_ptr.Pointer()->Set(NULL); 185} 186 187void MessageLoop::AddDestructionObserver( 188 DestructionObserver* destruction_observer) { 189 DCHECK(this == current()); 190 destruction_observers_.AddObserver(destruction_observer); 191} 192 193void MessageLoop::RemoveDestructionObserver( 194 DestructionObserver* destruction_observer) { 195 DCHECK(this == current()); 196 destruction_observers_.RemoveObserver(destruction_observer); 197} 198 199void MessageLoop::AddTaskObserver(TaskObserver* task_observer) { 200 DCHECK_EQ(this, current()); 201 task_observers_.AddObserver(task_observer); 202} 203 204void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) { 205 DCHECK_EQ(this, current()); 206 task_observers_.RemoveObserver(task_observer); 207} 208 209void MessageLoop::Run() { 210 AutoRunState save_state(this); 211 RunHandler(); 212} 213 214void MessageLoop::RunAllPending() { 215 AutoRunState save_state(this); 216 state_->quit_received = true; // Means run until we would otherwise block. 217 RunHandler(); 218} 219 220// Runs the loop in two different SEH modes: 221// enable_SEH_restoration_ = false : any unhandled exception goes to the last 222// one that calls SetUnhandledExceptionFilter(). 223// enable_SEH_restoration_ = true : any unhandled exception goes to the filter 224// that was existed before the loop was run. 225void MessageLoop::RunHandler() { 226#if defined(OS_WIN) 227 if (exception_restoration_) { 228 RunInternalInSEHFrame(); 229 return; 230 } 231#endif 232 233 RunInternal(); 234} 235//------------------------------------------------------------------------------ 236#if defined(OS_WIN) 237__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() { 238 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); 239 __try { 240 RunInternal(); 241 } __except(SEHFilter(current_filter)) { 242 } 243 return; 244} 245#endif 246//------------------------------------------------------------------------------ 247 248void MessageLoop::RunInternal() { 249 DCHECK(this == current()); 250 251// StartHistogrammer(); 252 253#if !defined(OS_MACOSX) 254 if (state_->dispatcher && type() == TYPE_UI) { 255 static_cast<base::MessagePumpForUI*>(pump_.get())-> 256 RunWithDispatcher(this, state_->dispatcher); 257 return; 258 } 259#endif 260 261 pump_->Run(this); 262} 263 264//------------------------------------------------------------------------------ 265// Wrapper functions for use in above message loop framework. 266 267bool MessageLoop::ProcessNextDelayedNonNestableTask() { 268 if (state_->run_depth != 1) 269 return false; 270 271 if (deferred_non_nestable_work_queue_.empty()) 272 return false; 273 274 Task* task = deferred_non_nestable_work_queue_.front().task; 275 deferred_non_nestable_work_queue_.pop(); 276 277 RunTask(task); 278 return true; 279} 280 281//------------------------------------------------------------------------------ 282 283void MessageLoop::Quit() { 284 DCHECK(current() == this); 285 if (state_) { 286 state_->quit_received = true; 287 } else { 288 NOTREACHED() << "Must be inside Run to call Quit"; 289 } 290} 291 292void MessageLoop::QuitNow() { 293 DCHECK(current() == this); 294 if (state_) { 295 pump_->Quit(); 296 } else { 297 NOTREACHED() << "Must be inside Run to call Quit"; 298 } 299} 300 301void MessageLoop::PostTask( 302 const tracked_objects::Location& from_here, Task* task) { 303 PostTask_Helper(from_here, task, 0, true); 304} 305 306void MessageLoop::PostDelayedTask( 307 const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { 308 PostTask_Helper(from_here, task, delay_ms, true); 309} 310 311void MessageLoop::PostNonNestableTask( 312 const tracked_objects::Location& from_here, Task* task) { 313 PostTask_Helper(from_here, task, 0, false); 314} 315 316void MessageLoop::PostNonNestableDelayedTask( 317 const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { 318 PostTask_Helper(from_here, task, delay_ms, false); 319} 320 321// Possibly called on a background thread! 322void MessageLoop::PostTask_Helper( 323 const tracked_objects::Location& from_here, Task* task, int64 delay_ms, 324 bool nestable) { 325 task->SetBirthPlace(from_here); 326 327 PendingTask pending_task(task, nestable); 328 329 if (delay_ms > 0) { 330 pending_task.delayed_run_time = 331 Time::Now() + TimeDelta::FromMilliseconds(delay_ms); 332 333#if defined(OS_WIN) 334 if (high_resolution_timer_expiration_.is_null()) { 335 // Windows timers are granular to 15.6ms. If we only set high-res 336 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, 337 // which as a percentage is pretty inaccurate. So enable high 338 // res timers for any timer which is within 2x of the granularity. 339 // This is a tradeoff between accuracy and power management. 340 bool needs_high_res_timers = 341 delay_ms < (2 * Time::kMinLowResolutionThresholdMs); 342 if (needs_high_res_timers) { 343 Time::ActivateHighResolutionTimer(true); 344 high_resolution_timer_expiration_ = base::TimeTicks::Now() + 345 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); 346 } 347 } 348#endif 349 } else { 350 DCHECK_EQ(delay_ms, 0) << "delay should not be negative"; 351 } 352 353#if defined(OS_WIN) 354 if (!high_resolution_timer_expiration_.is_null()) { 355 if (base::TimeTicks::Now() > high_resolution_timer_expiration_) { 356 Time::ActivateHighResolutionTimer(false); 357 high_resolution_timer_expiration_ = base::TimeTicks(); 358 } 359 } 360#endif 361 362 // Warning: Don't try to short-circuit, and handle this thread's tasks more 363 // directly, as it could starve handling of foreign threads. Put every task 364 // into this queue. 365 366 scoped_refptr<base::MessagePump> pump; 367 { 368 AutoLock locked(incoming_queue_lock_); 369 370 bool was_empty = incoming_queue_.empty(); 371 incoming_queue_.push(pending_task); 372 if (!was_empty) 373 return; // Someone else should have started the sub-pump. 374 375 pump = pump_; 376 } 377 // Since the incoming_queue_ may contain a task that destroys this message 378 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. 379 // We use a stack-based reference to the message pump so that we can call 380 // ScheduleWork outside of incoming_queue_lock_. 381 382 pump->ScheduleWork(); 383} 384 385void MessageLoop::SetNestableTasksAllowed(bool allowed) { 386 if (nestable_tasks_allowed_ != allowed) { 387 nestable_tasks_allowed_ = allowed; 388 if (!nestable_tasks_allowed_) 389 return; 390 // Start the native pump if we are not already pumping. 391 pump_->ScheduleWork(); 392 } 393} 394 395bool MessageLoop::NestableTasksAllowed() const { 396 return nestable_tasks_allowed_; 397} 398 399bool MessageLoop::IsNested() { 400 return state_->run_depth > 1; 401} 402 403//------------------------------------------------------------------------------ 404 405void MessageLoop::RunTask(Task* task) { 406 DCHECK(nestable_tasks_allowed_); 407 // Execute the task and assume the worst: It is probably not reentrant. 408 nestable_tasks_allowed_ = false; 409 410 HistogramEvent(kTaskRunEvent); 411 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 412 WillProcessTask(task->tracked_birth_time())); 413 task->Run(); 414 FOR_EACH_OBSERVER(TaskObserver, task_observers_, DidProcessTask()); 415 delete task; 416 417 nestable_tasks_allowed_ = true; 418} 419 420bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { 421 if (pending_task.nestable || state_->run_depth == 1) { 422 RunTask(pending_task.task); 423 // Show that we ran a task (Note: a new one might arrive as a 424 // consequence!). 425 return true; 426 } 427 428 // We couldn't run the task now because we're in a nested message loop 429 // and the task isn't nestable. 430 deferred_non_nestable_work_queue_.push(pending_task); 431 return false; 432} 433 434void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 435 // Move to the delayed work queue. Initialize the sequence number 436 // before inserting into the delayed_work_queue_. The sequence number 437 // is used to faciliate FIFO sorting when two tasks have the same 438 // delayed_run_time value. 439 PendingTask new_pending_task(pending_task); 440 new_pending_task.sequence_num = next_sequence_num_++; 441 delayed_work_queue_.push(new_pending_task); 442} 443 444void MessageLoop::ReloadWorkQueue() { 445 // We can improve performance of our loading tasks from incoming_queue_ to 446 // work_queue_ by waiting until the last minute (work_queue_ is empty) to 447 // load. That reduces the number of locks-per-task significantly when our 448 // queues get large. 449 if (!work_queue_.empty()) 450 return; // Wait till we *really* need to lock and load. 451 452 // Acquire all we can from the inter-thread queue with one lock acquisition. 453 { 454 AutoLock lock(incoming_queue_lock_); 455 if (incoming_queue_.empty()) 456 return; 457 incoming_queue_.Swap(&work_queue_); // Constant time 458 DCHECK(incoming_queue_.empty()); 459 } 460} 461 462bool MessageLoop::DeletePendingTasks() { 463 bool did_work = !work_queue_.empty(); 464 while (!work_queue_.empty()) { 465 PendingTask pending_task = work_queue_.front(); 466 work_queue_.pop(); 467 if (!pending_task.delayed_run_time.is_null()) { 468 // We want to delete delayed tasks in the same order in which they would 469 // normally be deleted in case of any funny dependencies between delayed 470 // tasks. 471 AddToDelayedWorkQueue(pending_task); 472 } else { 473 // TODO(darin): Delete all tasks once it is safe to do so. 474 // Until it is totally safe, just do it when running Purify or 475 // Valgrind. 476#if defined(PURIFY) 477 delete pending_task.task; 478#elif defined(OS_POSIX) 479 if (RUNNING_ON_VALGRIND) 480 delete pending_task.task; 481#endif // defined(OS_POSIX) 482 } 483 } 484 did_work |= !deferred_non_nestable_work_queue_.empty(); 485 while (!deferred_non_nestable_work_queue_.empty()) { 486 // TODO(darin): Delete all tasks once it is safe to do so. 487 // Until it is totaly safe, only delete them under Purify and Valgrind. 488 Task* task = NULL; 489#if defined(PURIFY) 490 task = deferred_non_nestable_work_queue_.front().task; 491#elif defined(OS_POSIX) 492 if (RUNNING_ON_VALGRIND) 493 task = deferred_non_nestable_work_queue_.front().task; 494#endif 495 deferred_non_nestable_work_queue_.pop(); 496 if (task) 497 delete task; 498 } 499 did_work |= !delayed_work_queue_.empty(); 500 while (!delayed_work_queue_.empty()) { 501 Task* task = delayed_work_queue_.top().task; 502 delayed_work_queue_.pop(); 503 delete task; 504 } 505 return did_work; 506} 507 508bool MessageLoop::DoWork() { 509 if (!nestable_tasks_allowed_) { 510 // Task can't be executed right now. 511 return false; 512 } 513 514 for (;;) { 515 ReloadWorkQueue(); 516 if (work_queue_.empty()) 517 break; 518 519 // Execute oldest task. 520 do { 521 PendingTask pending_task = work_queue_.front(); 522 work_queue_.pop(); 523 if (!pending_task.delayed_run_time.is_null()) { 524 AddToDelayedWorkQueue(pending_task); 525 // If we changed the topmost task, then it is time to re-schedule. 526 if (delayed_work_queue_.top().task == pending_task.task) 527 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 528 } else { 529 if (DeferOrRunPendingTask(pending_task)) 530 return true; 531 } 532 } while (!work_queue_.empty()); 533 } 534 535 // Nothing happened. 536 return false; 537} 538 539bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { 540 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 541 *next_delayed_work_time = Time(); 542 return false; 543 } 544 545 if (delayed_work_queue_.top().delayed_run_time > Time::Now()) { 546 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 547 return false; 548 } 549 550 PendingTask pending_task = delayed_work_queue_.top(); 551 delayed_work_queue_.pop(); 552 553 if (!delayed_work_queue_.empty()) 554 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 555 556 return DeferOrRunPendingTask(pending_task); 557} 558 559bool MessageLoop::DoIdleWork() { 560 if (ProcessNextDelayedNonNestableTask()) 561 return true; 562 563 if (state_->quit_received) 564 pump_->Quit(); 565 566 return false; 567} 568 569//------------------------------------------------------------------------------ 570// MessageLoop::AutoRunState 571 572MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) { 573 // Make the loop reference us. 574 previous_state_ = loop_->state_; 575 if (previous_state_) { 576 run_depth = previous_state_->run_depth + 1; 577 } else { 578 run_depth = 1; 579 } 580 loop_->state_ = this; 581 582 // Initialize the other fields: 583 quit_received = false; 584#if !defined(OS_MACOSX) 585 dispatcher = NULL; 586#endif 587} 588 589MessageLoop::AutoRunState::~AutoRunState() { 590 loop_->state_ = previous_state_; 591} 592 593//------------------------------------------------------------------------------ 594// MessageLoop::PendingTask 595 596bool MessageLoop::PendingTask::operator<(const PendingTask& other) const { 597 // Since the top of a priority queue is defined as the "greatest" element, we 598 // need to invert the comparison here. We want the smaller time to be at the 599 // top of the heap. 600 601 if (delayed_run_time < other.delayed_run_time) 602 return false; 603 604 if (delayed_run_time > other.delayed_run_time) 605 return true; 606 607 // If the times happen to match, then we use the sequence number to decide. 608 // Compare the difference to support integer roll-over. 609 return (sequence_num - other.sequence_num) > 0; 610} 611 612//------------------------------------------------------------------------------ 613// Method and data for histogramming events and actions taken by each instance 614// on each thread. 615 616// static 617void MessageLoop::EnableHistogrammer(bool enable) { 618 enable_histogrammer_ = enable; 619} 620 621void MessageLoop::StartHistogrammer() { 622 if (enable_histogrammer_ && !message_histogram_.get() 623 && StatisticsRecorder::WasStarted()) { 624 DCHECK(!thread_name_.empty()); 625 message_histogram_ = LinearHistogram::FactoryGet("MsgLoop:" + thread_name_, 626 kLeastNonZeroMessageId, kMaxMessageId, 627 kNumberOfDistinctMessagesDisplayed, 628 message_histogram_->kHexRangePrintingFlag); 629 message_histogram_->SetRangeDescriptions(event_descriptions_); 630 } 631} 632 633void MessageLoop::HistogramEvent(int event) { 634 if (message_histogram_.get()) 635 message_histogram_->Add(event); 636} 637 638//------------------------------------------------------------------------------ 639// MessageLoopForUI 640 641#if defined(OS_WIN) 642void MessageLoopForUI::DidProcessMessage(const MSG& message) { 643 pump_win()->DidProcessMessage(message); 644} 645#endif // defined(OS_WIN) 646 647#if !defined(OS_MACOSX) && !defined(ANDROID) 648void MessageLoopForUI::AddObserver(Observer* observer) { 649 pump_ui()->AddObserver(observer); 650} 651 652void MessageLoopForUI::RemoveObserver(Observer* observer) { 653 pump_ui()->RemoveObserver(observer); 654} 655 656void MessageLoopForUI::Run(Dispatcher* dispatcher) { 657 AutoRunState save_state(this); 658 state_->dispatcher = dispatcher; 659 RunHandler(); 660} 661#endif // !defined(OS_MACOSX) 662 663//------------------------------------------------------------------------------ 664// MessageLoopForIO 665 666#if defined(OS_WIN) 667 668void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 669 pump_io()->RegisterIOHandler(file, handler); 670} 671 672bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 673 return pump_io()->WaitForIOCompletion(timeout, filter); 674} 675 676#elif defined(OS_POSIX) 677 678bool MessageLoopForIO::WatchFileDescriptor(int fd, 679 bool persistent, 680 Mode mode, 681 FileDescriptorWatcher *controller, 682 Watcher *delegate) { 683 return pump_libevent()->WatchFileDescriptor( 684 fd, 685 persistent, 686 static_cast<base::MessagePumpLibevent::Mode>(mode), 687 controller, 688 delegate); 689} 690 691#endif 692