message_loop.cc revision 731df977c0511bca2206b5f333555b1205ff1f43
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/lazy_instance.h" 11#include "base/logging.h" 12#include "base/message_pump_default.h" 13#include "base/metrics/histogram.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 base::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#ifndef ANDROID 252 StartHistogrammer(); 253#endif 254 255#if !defined(OS_MACOSX) 256 if (state_->dispatcher && type() == TYPE_UI) { 257 static_cast<base::MessagePumpForUI*>(pump_.get())-> 258 RunWithDispatcher(this, state_->dispatcher); 259 return; 260 } 261#endif 262 263 pump_->Run(this); 264} 265 266//------------------------------------------------------------------------------ 267// Wrapper functions for use in above message loop framework. 268 269bool MessageLoop::ProcessNextDelayedNonNestableTask() { 270 if (state_->run_depth != 1) 271 return false; 272 273 if (deferred_non_nestable_work_queue_.empty()) 274 return false; 275 276 Task* task = deferred_non_nestable_work_queue_.front().task; 277 deferred_non_nestable_work_queue_.pop(); 278 279 RunTask(task); 280 return true; 281} 282 283//------------------------------------------------------------------------------ 284 285void MessageLoop::Quit() { 286 DCHECK(current() == this); 287 if (state_) { 288 state_->quit_received = true; 289 } else { 290 NOTREACHED() << "Must be inside Run to call Quit"; 291 } 292} 293 294void MessageLoop::QuitNow() { 295 DCHECK(current() == this); 296 if (state_) { 297 pump_->Quit(); 298 } else { 299 NOTREACHED() << "Must be inside Run to call Quit"; 300 } 301} 302 303void MessageLoop::PostTask( 304 const tracked_objects::Location& from_here, Task* task) { 305 PostTask_Helper(from_here, task, 0, true); 306} 307 308void MessageLoop::PostDelayedTask( 309 const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { 310 PostTask_Helper(from_here, task, delay_ms, true); 311} 312 313void MessageLoop::PostNonNestableTask( 314 const tracked_objects::Location& from_here, Task* task) { 315 PostTask_Helper(from_here, task, 0, false); 316} 317 318void MessageLoop::PostNonNestableDelayedTask( 319 const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { 320 PostTask_Helper(from_here, task, delay_ms, false); 321} 322 323// Possibly called on a background thread! 324void MessageLoop::PostTask_Helper( 325 const tracked_objects::Location& from_here, Task* task, int64 delay_ms, 326 bool nestable) { 327 task->SetBirthPlace(from_here); 328 329 PendingTask pending_task(task, nestable); 330 331 if (delay_ms > 0) { 332 pending_task.delayed_run_time = 333 Time::Now() + TimeDelta::FromMilliseconds(delay_ms); 334 335#if defined(OS_WIN) 336 if (high_resolution_timer_expiration_.is_null()) { 337 // Windows timers are granular to 15.6ms. If we only set high-res 338 // timers for those under 15.6ms, then a 18ms timer ticks at ~32ms, 339 // which as a percentage is pretty inaccurate. So enable high 340 // res timers for any timer which is within 2x of the granularity. 341 // This is a tradeoff between accuracy and power management. 342 bool needs_high_res_timers = 343 delay_ms < (2 * Time::kMinLowResolutionThresholdMs); 344 if (needs_high_res_timers) { 345 Time::ActivateHighResolutionTimer(true); 346 high_resolution_timer_expiration_ = base::TimeTicks::Now() + 347 TimeDelta::FromMilliseconds(kHighResolutionTimerModeLeaseTimeMs); 348 } 349 } 350#endif 351 } else { 352 DCHECK_EQ(delay_ms, 0) << "delay should not be negative"; 353 } 354 355#if defined(OS_WIN) 356 if (!high_resolution_timer_expiration_.is_null()) { 357 if (base::TimeTicks::Now() > high_resolution_timer_expiration_) { 358 Time::ActivateHighResolutionTimer(false); 359 high_resolution_timer_expiration_ = base::TimeTicks(); 360 } 361 } 362#endif 363 364 // Warning: Don't try to short-circuit, and handle this thread's tasks more 365 // directly, as it could starve handling of foreign threads. Put every task 366 // into this queue. 367 368 scoped_refptr<base::MessagePump> pump; 369 { 370 AutoLock locked(incoming_queue_lock_); 371 372 bool was_empty = incoming_queue_.empty(); 373 incoming_queue_.push(pending_task); 374 if (!was_empty) 375 return; // Someone else should have started the sub-pump. 376 377 pump = pump_; 378 } 379 // Since the incoming_queue_ may contain a task that destroys this message 380 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. 381 // We use a stack-based reference to the message pump so that we can call 382 // ScheduleWork outside of incoming_queue_lock_. 383 384 pump->ScheduleWork(); 385} 386 387void MessageLoop::SetNestableTasksAllowed(bool allowed) { 388 if (nestable_tasks_allowed_ != allowed) { 389 nestable_tasks_allowed_ = allowed; 390 if (!nestable_tasks_allowed_) 391 return; 392 // Start the native pump if we are not already pumping. 393 pump_->ScheduleWork(); 394 } 395} 396 397bool MessageLoop::NestableTasksAllowed() const { 398 return nestable_tasks_allowed_; 399} 400 401bool MessageLoop::IsNested() { 402 return state_->run_depth > 1; 403} 404 405//------------------------------------------------------------------------------ 406 407void MessageLoop::RunTask(Task* task) { 408 DCHECK(nestable_tasks_allowed_); 409 // Execute the task and assume the worst: It is probably not reentrant. 410 nestable_tasks_allowed_ = false; 411 412 HistogramEvent(kTaskRunEvent); 413 FOR_EACH_OBSERVER(TaskObserver, task_observers_, 414 WillProcessTask(task->tracked_birth_time())); 415 task->Run(); 416 FOR_EACH_OBSERVER(TaskObserver, task_observers_, DidProcessTask()); 417 delete task; 418 419 nestable_tasks_allowed_ = true; 420} 421 422bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) { 423 if (pending_task.nestable || state_->run_depth == 1) { 424 RunTask(pending_task.task); 425 // Show that we ran a task (Note: a new one might arrive as a 426 // consequence!). 427 return true; 428 } 429 430 // We couldn't run the task now because we're in a nested message loop 431 // and the task isn't nestable. 432 deferred_non_nestable_work_queue_.push(pending_task); 433 return false; 434} 435 436void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 437 // Move to the delayed work queue. Initialize the sequence number 438 // before inserting into the delayed_work_queue_. The sequence number 439 // is used to faciliate FIFO sorting when two tasks have the same 440 // delayed_run_time value. 441 PendingTask new_pending_task(pending_task); 442 new_pending_task.sequence_num = next_sequence_num_++; 443 delayed_work_queue_.push(new_pending_task); 444} 445 446void MessageLoop::ReloadWorkQueue() { 447 // We can improve performance of our loading tasks from incoming_queue_ to 448 // work_queue_ by waiting until the last minute (work_queue_ is empty) to 449 // load. That reduces the number of locks-per-task significantly when our 450 // queues get large. 451 if (!work_queue_.empty()) 452 return; // Wait till we *really* need to lock and load. 453 454 // Acquire all we can from the inter-thread queue with one lock acquisition. 455 { 456 AutoLock lock(incoming_queue_lock_); 457 if (incoming_queue_.empty()) 458 return; 459 incoming_queue_.Swap(&work_queue_); // Constant time 460 DCHECK(incoming_queue_.empty()); 461 } 462} 463 464bool MessageLoop::DeletePendingTasks() { 465 bool did_work = !work_queue_.empty(); 466 while (!work_queue_.empty()) { 467 PendingTask pending_task = work_queue_.front(); 468 work_queue_.pop(); 469 if (!pending_task.delayed_run_time.is_null()) { 470 // We want to delete delayed tasks in the same order in which they would 471 // normally be deleted in case of any funny dependencies between delayed 472 // tasks. 473 AddToDelayedWorkQueue(pending_task); 474 } else { 475 // TODO(darin): Delete all tasks once it is safe to do so. 476 // Until it is totally safe, just do it when running Purify or 477 // Valgrind. 478#if defined(PURIFY) 479 delete pending_task.task; 480#elif defined(OS_POSIX) 481 if (RUNNING_ON_VALGRIND) 482 delete pending_task.task; 483#endif // defined(OS_POSIX) 484 } 485 } 486 did_work |= !deferred_non_nestable_work_queue_.empty(); 487 while (!deferred_non_nestable_work_queue_.empty()) { 488 // TODO(darin): Delete all tasks once it is safe to do so. 489 // Until it is totaly safe, only delete them under Purify and Valgrind. 490 Task* task = NULL; 491#if defined(PURIFY) 492 task = deferred_non_nestable_work_queue_.front().task; 493#elif defined(OS_POSIX) 494 if (RUNNING_ON_VALGRIND) 495 task = deferred_non_nestable_work_queue_.front().task; 496#endif 497 deferred_non_nestable_work_queue_.pop(); 498 if (task) 499 delete task; 500 } 501 did_work |= !delayed_work_queue_.empty(); 502 while (!delayed_work_queue_.empty()) { 503 Task* task = delayed_work_queue_.top().task; 504 delayed_work_queue_.pop(); 505 delete task; 506 } 507 return did_work; 508} 509 510bool MessageLoop::DoWork() { 511 if (!nestable_tasks_allowed_) { 512 // Task can't be executed right now. 513 return false; 514 } 515 516 for (;;) { 517 ReloadWorkQueue(); 518 if (work_queue_.empty()) 519 break; 520 521 // Execute oldest task. 522 do { 523 PendingTask pending_task = work_queue_.front(); 524 work_queue_.pop(); 525 if (!pending_task.delayed_run_time.is_null()) { 526 AddToDelayedWorkQueue(pending_task); 527 // If we changed the topmost task, then it is time to re-schedule. 528 if (delayed_work_queue_.top().task == pending_task.task) 529 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 530 } else { 531 if (DeferOrRunPendingTask(pending_task)) 532 return true; 533 } 534 } while (!work_queue_.empty()); 535 } 536 537 // Nothing happened. 538 return false; 539} 540 541bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { 542 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 543 *next_delayed_work_time = Time(); 544 return false; 545 } 546 547 if (delayed_work_queue_.top().delayed_run_time > Time::Now()) { 548 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 549 return false; 550 } 551 552 PendingTask pending_task = delayed_work_queue_.top(); 553 delayed_work_queue_.pop(); 554 555 if (!delayed_work_queue_.empty()) 556 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 557 558 return DeferOrRunPendingTask(pending_task); 559} 560 561bool MessageLoop::DoIdleWork() { 562 if (ProcessNextDelayedNonNestableTask()) 563 return true; 564 565 if (state_->quit_received) 566 pump_->Quit(); 567 568 return false; 569} 570 571//------------------------------------------------------------------------------ 572// MessageLoop::AutoRunState 573 574MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) { 575 // Make the loop reference us. 576 previous_state_ = loop_->state_; 577 if (previous_state_) { 578 run_depth = previous_state_->run_depth + 1; 579 } else { 580 run_depth = 1; 581 } 582 loop_->state_ = this; 583 584 // Initialize the other fields: 585 quit_received = false; 586#if !defined(OS_MACOSX) 587 dispatcher = NULL; 588#endif 589} 590 591MessageLoop::AutoRunState::~AutoRunState() { 592 loop_->state_ = previous_state_; 593} 594 595//------------------------------------------------------------------------------ 596// MessageLoop::PendingTask 597 598bool MessageLoop::PendingTask::operator<(const PendingTask& other) const { 599 // Since the top of a priority queue is defined as the "greatest" element, we 600 // need to invert the comparison here. We want the smaller time to be at the 601 // top of the heap. 602 603 if (delayed_run_time < other.delayed_run_time) 604 return false; 605 606 if (delayed_run_time > other.delayed_run_time) 607 return true; 608 609 // If the times happen to match, then we use the sequence number to decide. 610 // Compare the difference to support integer roll-over. 611 return (sequence_num - other.sequence_num) > 0; 612} 613 614//------------------------------------------------------------------------------ 615// Method and data for histogramming events and actions taken by each instance 616// on each thread. 617 618// static 619void MessageLoop::EnableHistogrammer(bool enable) { 620 enable_histogrammer_ = enable; 621} 622 623void MessageLoop::StartHistogrammer() { 624 if (enable_histogrammer_ && !message_histogram_.get() 625 && base::StatisticsRecorder::WasStarted()) { 626 DCHECK(!thread_name_.empty()); 627 message_histogram_ = base::LinearHistogram::FactoryGet( 628 "MsgLoop:" + thread_name_, 629 kLeastNonZeroMessageId, kMaxMessageId, 630 kNumberOfDistinctMessagesDisplayed, 631 message_histogram_->kHexRangePrintingFlag); 632 message_histogram_->SetRangeDescriptions(event_descriptions_); 633 } 634} 635 636void MessageLoop::HistogramEvent(int event) { 637 if (message_histogram_.get()) 638 message_histogram_->Add(event); 639} 640 641//------------------------------------------------------------------------------ 642// MessageLoopForUI 643 644#if defined(OS_WIN) 645void MessageLoopForUI::DidProcessMessage(const MSG& message) { 646 pump_win()->DidProcessMessage(message); 647} 648#endif // defined(OS_WIN) 649 650#if !defined(OS_MACOSX) && !defined(ANDROID) 651void MessageLoopForUI::AddObserver(Observer* observer) { 652 pump_ui()->AddObserver(observer); 653} 654 655void MessageLoopForUI::RemoveObserver(Observer* observer) { 656 pump_ui()->RemoveObserver(observer); 657} 658 659void MessageLoopForUI::Run(Dispatcher* dispatcher) { 660 AutoRunState save_state(this); 661 state_->dispatcher = dispatcher; 662 RunHandler(); 663} 664#endif // !defined(OS_MACOSX) 665 666//------------------------------------------------------------------------------ 667// MessageLoopForIO 668 669#if defined(OS_WIN) 670 671void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 672 pump_io()->RegisterIOHandler(file, handler); 673} 674 675bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 676 return pump_io()->WaitForIOCompletion(timeout, filter); 677} 678 679#elif defined(OS_POSIX) 680 681bool MessageLoopForIO::WatchFileDescriptor(int fd, 682 bool persistent, 683 Mode mode, 684 FileDescriptorWatcher *controller, 685 Watcher *delegate) { 686 return pump_libevent()->WatchFileDescriptor( 687 fd, 688 persistent, 689 static_cast<base::MessagePumpLibevent::Mode>(mode), 690 controller, 691 delegate); 692} 693 694#endif 695