message_loop.cc (22939B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 #include "base/message_loop.h" 8 9 #include <algorithm> 10 11 #include "base/logging.h" 12 #include "base/message_pump_default.h" 13 #include "base/string_util.h" 14 #include "base/thread_local.h" 15 #include "mozilla/Atomics.h" 16 #include "mozilla/MaybeLeakRefPtr.h" 17 #include "mozilla/Mutex.h" 18 #include "mozilla/ProfilerRunnable.h" 19 #include "mozilla/TargetShutdownTaskSet.h" 20 #include "nsIEventTarget.h" 21 #include "nsITargetShutdownTask.h" 22 #include "nsThreadUtils.h" 23 24 #if defined(XP_DARWIN) 25 # include "base/message_pump_mac.h" 26 # include "base/message_pump_kqueue.h" 27 #endif 28 #if defined(XP_UNIX) && !defined(XP_DARWIN) 29 # include "base/message_pump_libevent.h" 30 #endif 31 #if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \ 32 defined(XP_NETBSD) || defined(XP_OPENBSD) 33 # if defined(MOZ_WIDGET_GTK) 34 # include "base/message_pump_glib.h" 35 # endif 36 #endif 37 #ifdef ANDROID 38 # include "base/message_pump_android.h" 39 #endif 40 #include "nsISerialEventTarget.h" 41 42 #include "mozilla/ipc/MessagePump.h" 43 #include "nsThreadUtils.h" 44 45 using base::Time; 46 using base::TimeDelta; 47 using base::TimeTicks; 48 49 using mozilla::Runnable; 50 51 static base::ThreadLocalPointer<MessageLoop>& get_tls_ptr() { 52 static base::ThreadLocalPointer<MessageLoop> tls_ptr; 53 return tls_ptr; 54 } 55 56 //------------------------------------------------------------------------------ 57 58 #if defined(XP_WIN) 59 60 // Upon a SEH exception in this thread, it restores the original unhandled 61 // exception filter. 62 static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) { 63 ::SetUnhandledExceptionFilter(old_filter); 64 return EXCEPTION_CONTINUE_SEARCH; 65 } 66 67 // Retrieves a pointer to the current unhandled exception filter. There 68 // is no standalone getter method. 69 static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() { 70 LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL; 71 top_filter = ::SetUnhandledExceptionFilter(0); 72 ::SetUnhandledExceptionFilter(top_filter); 73 return top_filter; 74 } 75 76 #endif // defined(XP_WIN) 77 78 //------------------------------------------------------------------------------ 79 80 class MessageLoop::EventTarget : public nsISerialEventTarget, 81 public nsITargetShutdownTask, 82 public MessageLoop::DestructionObserver { 83 public: 84 NS_DECL_THREADSAFE_ISUPPORTS 85 NS_DECL_NSIEVENTTARGET_FULL 86 87 void TargetShutdown() override { 88 TargetShutdownTaskSet::TasksArray shutdownTasks; 89 { 90 mozilla::MutexAutoLock lock(mMutex); 91 if (mShutdownTasksRun) { 92 return; 93 } 94 shutdownTasks = mShutdownTasks.Extract(); 95 } 96 for (const auto& task : shutdownTasks) { 97 task->TargetShutdown(); 98 } 99 } 100 101 explicit EventTarget(MessageLoop* aLoop) 102 : mMutex("MessageLoop::EventTarget"), mLoop(aLoop) { 103 aLoop->AddDestructionObserver(this); 104 } 105 106 private: 107 virtual ~EventTarget() { 108 if (mLoop) { 109 mLoop->RemoveDestructionObserver(this); 110 } 111 } 112 113 void WillDestroyCurrentMessageLoop() override { 114 { 115 mozilla::MutexAutoLock lock(mMutex); 116 // The MessageLoop is being destroyed and we are called from its 117 // destructor There's no real need to remove ourselves from the 118 // destruction observer list. But it makes things look tidier. 119 mLoop->RemoveDestructionObserver(this); 120 mLoop = nullptr; 121 } 122 123 TargetShutdown(); 124 } 125 126 mozilla::Mutex mMutex; 127 bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false; 128 TargetShutdownTaskSet mShutdownTasks MOZ_GUARDED_BY(mMutex); 129 MessageLoop* mLoop MOZ_GUARDED_BY(mMutex); 130 }; 131 132 NS_IMPL_ISUPPORTS(MessageLoop::EventTarget, nsIEventTarget, 133 nsISerialEventTarget) 134 135 NS_IMETHODIMP_(bool) 136 MessageLoop::EventTarget::IsOnCurrentThreadInfallible() { 137 mozilla::MutexAutoLock lock(mMutex); 138 return mLoop == MessageLoop::current(); 139 } 140 141 NS_IMETHODIMP 142 MessageLoop::EventTarget::IsOnCurrentThread(bool* aResult) { 143 *aResult = IsOnCurrentThreadInfallible(); 144 return NS_OK; 145 } 146 147 NS_IMETHODIMP 148 MessageLoop::EventTarget::DispatchFromScript(nsIRunnable* aEvent, 149 DispatchFlags aFlags) { 150 return Dispatch(do_AddRef(aEvent), aFlags); 151 } 152 153 NS_IMETHODIMP 154 MessageLoop::EventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent, 155 DispatchFlags aFlags) { 156 mozilla::MaybeLeakRefPtr<nsIRunnable> event(std::move(aEvent), 157 aFlags & NS_DISPATCH_FALLIBLE); 158 159 mozilla::MutexAutoLock lock(mMutex); 160 if (!mLoop) { 161 return NS_ERROR_NOT_INITIALIZED; 162 } 163 164 mLoop->PostTask(event.forget()); 165 return NS_OK; 166 } 167 168 NS_IMETHODIMP 169 MessageLoop::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent, 170 uint32_t aDelayMs) { 171 mozilla::MutexAutoLock lock(mMutex); 172 if (!mLoop || mShutdownTasksRun) { 173 return NS_ERROR_NOT_INITIALIZED; 174 } 175 176 mLoop->PostDelayedTask(std::move(aEvent), aDelayMs); 177 return NS_OK; 178 } 179 180 NS_IMETHODIMP 181 MessageLoop::EventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) { 182 mozilla::MutexAutoLock lock(mMutex); 183 if (!mLoop || mShutdownTasksRun) { 184 return NS_ERROR_UNEXPECTED; 185 } 186 mShutdownTasks.AddTask(aTask); 187 return NS_OK; 188 } 189 190 NS_IMETHODIMP 191 MessageLoop::EventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) { 192 mozilla::MutexAutoLock lock(mMutex); 193 if (!mLoop) { 194 return NS_ERROR_UNEXPECTED; 195 } 196 return mShutdownTasks.RemoveTask(aTask); 197 } 198 199 //------------------------------------------------------------------------------ 200 201 // static 202 MessageLoop* MessageLoop::current() { return get_tls_ptr().Get(); } 203 204 // static 205 void MessageLoop::set_current(MessageLoop* loop) { get_tls_ptr().Set(loop); } 206 207 static mozilla::Atomic<int32_t> message_loop_id_seq(0); 208 209 MessageLoop::MessageLoop(Type type, nsISerialEventTarget* aEventTarget) 210 : type_(type), 211 id_(++message_loop_id_seq), 212 nestable_tasks_allowed_(true), 213 exception_restoration_(false), 214 incoming_queue_lock_("MessageLoop Incoming Queue Lock"), 215 state_(NULL), 216 run_depth_base_(1), 217 shutting_down_(false), 218 #ifdef XP_WIN 219 os_modal_loop_(false), 220 #endif // XP_WIN 221 transient_hang_timeout_(0), 222 permanent_hang_timeout_(0), 223 next_sequence_num_(0) { 224 DCHECK(!current()) << "should only have one message loop per thread"; 225 get_tls_ptr().Set(this); 226 227 // Must initialize after current() is initialized. 228 mEventTarget = new EventTarget(this); 229 230 switch (type_) { 231 case TYPE_MOZILLA_PARENT: 232 MOZ_RELEASE_ASSERT(!aEventTarget); 233 pump_ = new mozilla::ipc::MessagePump(aEventTarget); 234 return; 235 case TYPE_MOZILLA_CHILD: 236 MOZ_RELEASE_ASSERT(!aEventTarget); 237 pump_ = new mozilla::ipc::MessagePumpForChildProcess(); 238 // There is a MessageLoop Run call from XRE_InitChildProcess 239 // and another one from MessagePumpForChildProcess. The one 240 // from MessagePumpForChildProcess becomes the base, so we need 241 // to set run_depth_base_ to 2 or we'll never be able to process 242 // Idle tasks. 243 run_depth_base_ = 2; 244 return; 245 case TYPE_MOZILLA_NONMAINTHREAD: 246 pump_ = new mozilla::ipc::MessagePumpForNonMainThreads(aEventTarget); 247 return; 248 #if defined(XP_WIN) || defined(XP_DARWIN) 249 case TYPE_MOZILLA_NONMAINUITHREAD: 250 pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads(aEventTarget); 251 return; 252 #elif defined(MOZ_WIDGET_ANDROID) 253 case TYPE_MOZILLA_ANDROID_UI: 254 MOZ_RELEASE_ASSERT(aEventTarget); 255 pump_ = new mozilla::ipc::MessagePumpForAndroidUI(aEventTarget); 256 return; 257 #endif // defined(MOZ_WIDGET_ANDROID) 258 default: 259 // Create one of Chromium's standard MessageLoop types below. 260 break; 261 } 262 263 #if defined(XP_WIN) 264 // TODO(rvargas): Get rid of the OS guards. 265 if (type_ == TYPE_DEFAULT) { 266 pump_ = new base::MessagePumpDefault(); 267 } else if (type_ == TYPE_IO) { 268 pump_ = new base::MessagePumpForIO(); 269 } else { 270 DCHECK(type_ == TYPE_UI); 271 pump_ = new base::MessagePumpForUI(); 272 } 273 #else 274 if (type_ == TYPE_UI) { 275 # if defined(XP_DARWIN) 276 pump_ = base::MessagePumpMac::Create(); 277 # elif defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \ 278 defined(XP_NETBSD) || defined(XP_OPENBSD) 279 pump_ = new base::MessagePumpForUI(); 280 # endif // XP_LINUX 281 } else if (type_ == TYPE_IO) { 282 # if defined(XP_DARWIN) 283 pump_ = new base::MessagePumpKqueue(); 284 # else 285 pump_ = new base::MessagePumpLibevent(); 286 # endif 287 } else { 288 pump_ = new base::MessagePumpDefault(); 289 } 290 #endif 291 292 // We want GetCurrentSerialEventTarget() to return the real nsThread if it 293 // will be used to dispatch tasks. However, under all other cases; we'll want 294 // it to return this MessageLoop's EventTarget. 295 if (nsISerialEventTarget* thread = pump_->GetXPCOMThread()) { 296 MOZ_ALWAYS_SUCCEEDS(thread->RegisterShutdownTask(mEventTarget)); 297 } else { 298 mozilla::SerialEventTargetGuard::Set(mEventTarget); 299 } 300 } 301 302 MessageLoop::~MessageLoop() { 303 DCHECK(this == current()); 304 305 // Let interested parties have one last shot at accessing this. 306 FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_, 307 WillDestroyCurrentMessageLoop()); 308 309 DCHECK(!state_); 310 311 // Clean up any unprocessed tasks, but take care: deleting a task could 312 // result in the addition of more tasks (e.g., via DeleteSoon). We set a 313 // limit on the number of times we will allow a deleted task to generate more 314 // tasks. Normally, we should only pass through this loop once or twice. If 315 // we end up hitting the loop limit, then it is probably due to one task that 316 // is being stubborn. Inspect the queues to see who is left. 317 bool did_work; 318 for (int i = 0; i < 100; ++i) { 319 DeletePendingTasks(); 320 ReloadWorkQueue(); 321 // If we end up with empty queues, then break out of the loop. 322 did_work = DeletePendingTasks(); 323 if (!did_work) break; 324 } 325 DCHECK(!did_work); 326 327 // OK, now make it so that no one can find us. 328 get_tls_ptr().Set(NULL); 329 } 330 331 void MessageLoop::AddDestructionObserver(DestructionObserver* obs) { 332 DCHECK(this == current()); 333 destruction_observers_.AddObserver(obs); 334 } 335 336 void MessageLoop::RemoveDestructionObserver(DestructionObserver* obs) { 337 DCHECK(this == current()); 338 destruction_observers_.RemoveObserver(obs); 339 } 340 341 void MessageLoop::Run() { 342 AutoRunState save_state(this); 343 RunHandler(); 344 } 345 346 // Runs the loop in two different SEH modes: 347 // enable_SEH_restoration_ = false : any unhandled exception goes to the last 348 // one that calls SetUnhandledExceptionFilter(). 349 // enable_SEH_restoration_ = true : any unhandled exception goes to the filter 350 // that was existed before the loop was run. 351 void MessageLoop::RunHandler() { 352 #if defined(XP_WIN) 353 if (exception_restoration_) { 354 LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter(); 355 MOZ_SEH_TRY { RunInternal(); } 356 MOZ_SEH_EXCEPT(SEHFilter(current_filter)) {} 357 return; 358 } 359 #endif 360 361 RunInternal(); 362 } 363 364 //------------------------------------------------------------------------------ 365 366 void MessageLoop::RunInternal() { 367 DCHECK(this == current()); 368 pump_->Run(this); 369 } 370 371 //------------------------------------------------------------------------------ 372 // Wrapper functions for use in above message loop framework. 373 374 bool MessageLoop::ProcessNextDelayedNonNestableTask() { 375 if (state_->run_depth > run_depth_base_) return false; 376 377 if (deferred_non_nestable_work_queue_.empty()) return false; 378 379 nsCOMPtr<nsIRunnable> task = 380 std::move(deferred_non_nestable_work_queue_.front().task); 381 deferred_non_nestable_work_queue_.pop(); 382 383 RunTask(task.forget()); 384 return true; 385 } 386 387 //------------------------------------------------------------------------------ 388 389 void MessageLoop::Quit() { 390 DCHECK(current() == this); 391 if (state_) { 392 state_->quit_received = true; 393 } else { 394 NOTREACHED() << "Must be inside Run to call Quit"; 395 } 396 } 397 398 void MessageLoop::PostTask(already_AddRefed<nsIRunnable> task) { 399 PostTask_Helper(std::move(task), 0); 400 } 401 402 void MessageLoop::PostDelayedTask(already_AddRefed<nsIRunnable> task, 403 int delay_ms) { 404 PostTask_Helper(std::move(task), delay_ms); 405 } 406 407 void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) { 408 DCHECK(current() == this); 409 MOZ_ASSERT(NS_IsMainThread()); 410 411 PendingTask pending_task(std::move(task), false); 412 mozilla::LogRunnable::LogDispatch(pending_task.task.get()); 413 deferred_non_nestable_work_queue_.push(std::move(pending_task)); 414 } 415 416 // Possibly called on a background thread! 417 void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task, 418 int delay_ms) { 419 if (nsISerialEventTarget* target = pump_->GetXPCOMThread()) { 420 nsresult rv; 421 if (delay_ms) { 422 rv = target->DelayedDispatch(std::move(task), delay_ms); 423 } else { 424 rv = target->Dispatch(std::move(task), NS_DISPATCH_NORMAL); 425 } 426 MOZ_ALWAYS_SUCCEEDS(rv); 427 return; 428 } 429 430 // Tasks should only be queued before or during the Run loop, not after. 431 MOZ_ASSERT(!shutting_down_); 432 433 PendingTask pending_task(std::move(task), true); 434 435 if (delay_ms > 0) { 436 pending_task.delayed_run_time = 437 TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms); 438 } else { 439 DCHECK(delay_ms == 0) << "delay should not be negative"; 440 } 441 442 // Warning: Don't try to short-circuit, and handle this thread's tasks more 443 // directly, as it could starve handling of foreign threads. Put every task 444 // into this queue. 445 446 RefPtr<base::MessagePump> pump; 447 { 448 mozilla::MutexAutoLock locked(incoming_queue_lock_); 449 mozilla::LogRunnable::LogDispatch(pending_task.task.get()); 450 incoming_queue_.push(std::move(pending_task)); 451 pump = pump_; 452 } 453 // Since the incoming_queue_ may contain a task that destroys this message 454 // loop, we cannot exit incoming_queue_lock_ until we are done with |this|. 455 // We use a stack-based reference to the message pump so that we can call 456 // ScheduleWork outside of incoming_queue_lock_. 457 458 pump->ScheduleWork(); 459 } 460 461 void MessageLoop::SetNestableTasksAllowed(bool allowed) { 462 if (nestable_tasks_allowed_ != allowed) { 463 nestable_tasks_allowed_ = allowed; 464 if (!nestable_tasks_allowed_) return; 465 // Start the native pump if we are not already pumping. 466 pump_->ScheduleWorkForNestedLoop(); 467 } 468 } 469 470 void MessageLoop::ScheduleWork() { 471 // Start the native pump if we are not already pumping. 472 pump_->ScheduleWork(); 473 } 474 475 bool MessageLoop::NestableTasksAllowed() const { 476 return nestable_tasks_allowed_; 477 } 478 479 //------------------------------------------------------------------------------ 480 481 void MessageLoop::RunTask(already_AddRefed<nsIRunnable> aTask) { 482 DCHECK(nestable_tasks_allowed_); 483 // Execute the task and assume the worst: It is probably not reentrant. 484 nestable_tasks_allowed_ = false; 485 486 nsCOMPtr<nsIRunnable> task = aTask; 487 488 { 489 mozilla::LogRunnable::Run log(task.get()); 490 AUTO_PROFILE_FOLLOWING_RUNNABLE(task); 491 task->Run(); 492 task = nullptr; 493 } 494 495 nestable_tasks_allowed_ = true; 496 } 497 498 bool MessageLoop::DeferOrRunPendingTask(PendingTask&& pending_task) { 499 if (pending_task.nestable || state_->run_depth <= run_depth_base_) { 500 RunTask(pending_task.task.forget()); 501 // Show that we ran a task (Note: a new one might arrive as a 502 // consequence!). 503 return true; 504 } 505 506 // We couldn't run the task now because we're in a nested message loop 507 // and the task isn't nestable. 508 mozilla::LogRunnable::LogDispatch(pending_task.task.get()); 509 deferred_non_nestable_work_queue_.push(std::move(pending_task)); 510 return false; 511 } 512 513 void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) { 514 // Move to the delayed work queue. Initialize the sequence number 515 // before inserting into the delayed_work_queue_. The sequence number 516 // is used to faciliate FIFO sorting when two tasks have the same 517 // delayed_run_time value. 518 PendingTask new_pending_task(pending_task); 519 new_pending_task.sequence_num = next_sequence_num_++; 520 mozilla::LogRunnable::LogDispatch(new_pending_task.task.get()); 521 delayed_work_queue_.push(std::move(new_pending_task)); 522 } 523 524 void MessageLoop::ReloadWorkQueue() { 525 // We can improve performance of our loading tasks from incoming_queue_ to 526 // work_queue_ by waiting until the last minute (work_queue_ is empty) to 527 // load. That reduces the number of locks-per-task significantly when our 528 // queues get large. 529 if (!work_queue_.empty()) 530 return; // Wait till we *really* need to lock and load. 531 532 // Acquire all we can from the inter-thread queue with one lock acquisition. 533 { 534 mozilla::MutexAutoLock lock(incoming_queue_lock_); 535 if (incoming_queue_.empty()) return; 536 std::swap(incoming_queue_, work_queue_); 537 DCHECK(incoming_queue_.empty()); 538 } 539 } 540 541 bool MessageLoop::DeletePendingTasks() { 542 MOZ_ASSERT(work_queue_.empty()); 543 bool did_work = !deferred_non_nestable_work_queue_.empty(); 544 while (!deferred_non_nestable_work_queue_.empty()) { 545 deferred_non_nestable_work_queue_.pop(); 546 } 547 did_work |= !delayed_work_queue_.empty(); 548 while (!delayed_work_queue_.empty()) { 549 delayed_work_queue_.pop(); 550 } 551 return did_work; 552 } 553 554 bool MessageLoop::DoWork() { 555 if (!nestable_tasks_allowed_) { 556 // Task can't be executed right now. 557 return false; 558 } 559 560 for (;;) { 561 ReloadWorkQueue(); 562 if (work_queue_.empty()) break; 563 564 // Execute oldest task. 565 do { 566 PendingTask pending_task = std::move(work_queue_.front()); 567 work_queue_.pop(); 568 if (!pending_task.delayed_run_time.is_null()) { 569 // NB: Don't move, because we use this later! 570 AddToDelayedWorkQueue(pending_task); 571 // If we changed the topmost task, then it is time to re-schedule. 572 if (delayed_work_queue_.top().task == pending_task.task) 573 pump_->ScheduleDelayedWork(pending_task.delayed_run_time); 574 } else { 575 if (DeferOrRunPendingTask(std::move(pending_task))) return true; 576 } 577 } while (!work_queue_.empty()); 578 } 579 580 // Nothing happened. 581 return false; 582 } 583 584 bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) { 585 if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { 586 *next_delayed_work_time = TimeTicks(); 587 return false; 588 } 589 590 if (delayed_work_queue_.top().delayed_run_time > TimeTicks::Now()) { 591 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 592 return false; 593 } 594 595 PendingTask pending_task = delayed_work_queue_.top(); 596 delayed_work_queue_.pop(); 597 598 if (!delayed_work_queue_.empty()) 599 *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time; 600 601 return DeferOrRunPendingTask(std::move(pending_task)); 602 } 603 604 bool MessageLoop::DoIdleWork() { 605 if (ProcessNextDelayedNonNestableTask()) return true; 606 607 if (state_->quit_received) pump_->Quit(); 608 609 return false; 610 } 611 612 //------------------------------------------------------------------------------ 613 // MessageLoop::AutoRunState 614 615 MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) { 616 // Top-level Run should only get called once. 617 MOZ_ASSERT(!loop_->shutting_down_); 618 619 // Make the loop reference us. 620 previous_state_ = loop_->state_; 621 if (previous_state_) { 622 run_depth = previous_state_->run_depth + 1; 623 } else { 624 run_depth = 1; 625 } 626 loop_->state_ = this; 627 628 // Initialize the other fields: 629 quit_received = false; 630 #if defined(XP_WIN) 631 dispatcher = NULL; 632 #endif 633 } 634 635 MessageLoop::AutoRunState::~AutoRunState() { 636 loop_->state_ = previous_state_; 637 638 // If exiting a top-level Run, then we're shutting down. 639 loop_->shutting_down_ = !previous_state_; 640 } 641 642 //------------------------------------------------------------------------------ 643 // MessageLoop::PendingTask 644 645 bool MessageLoop::PendingTask::operator<(const PendingTask& other) const { 646 // Since the top of a priority queue is defined as the "greatest" element, we 647 // need to invert the comparison here. We want the smaller time to be at the 648 // top of the heap. 649 650 if (delayed_run_time < other.delayed_run_time) return false; 651 652 if (delayed_run_time > other.delayed_run_time) return true; 653 654 // If the times happen to match, then we use the sequence number to decide. 655 // Compare the difference to support integer roll-over. 656 return (sequence_num - other.sequence_num) > 0; 657 } 658 659 //------------------------------------------------------------------------------ 660 // MessageLoop::SerialEventTarget 661 662 nsISerialEventTarget* MessageLoop::SerialEventTarget() { return mEventTarget; } 663 664 //------------------------------------------------------------------------------ 665 // MessageLoopForUI 666 667 #if defined(XP_WIN) 668 669 void MessageLoopForUI::Run(Dispatcher* dispatcher) { 670 AutoRunState save_state(this); 671 state_->dispatcher = dispatcher; 672 RunHandler(); 673 } 674 675 void MessageLoopForUI::AddObserver(Observer* observer) { 676 pump_win()->AddObserver(observer); 677 } 678 679 void MessageLoopForUI::RemoveObserver(Observer* observer) { 680 pump_win()->RemoveObserver(observer); 681 } 682 683 void MessageLoopForUI::WillProcessMessage(const MSG& message) { 684 pump_win()->WillProcessMessage(message); 685 } 686 void MessageLoopForUI::DidProcessMessage(const MSG& message) { 687 pump_win()->DidProcessMessage(message); 688 } 689 void MessageLoopForUI::PumpOutPendingPaintMessages() { 690 pump_ui()->PumpOutPendingPaintMessages(); 691 } 692 693 #endif // defined(XP_WIN) 694 695 //------------------------------------------------------------------------------ 696 // MessageLoopForIO 697 698 #if defined(XP_WIN) 699 700 void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) { 701 pump_io()->RegisterIOHandler(file, handler); 702 } 703 704 bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) { 705 return pump_io()->WaitForIOCompletion(timeout, filter); 706 } 707 708 #elif defined(XP_DARWIN) 709 710 bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, Mode mode, 711 FileDescriptorWatcher* controller, 712 Watcher* delegate) { 713 return pump_kqueue()->WatchFileDescriptor( 714 fd, persistent, static_cast<base::MessagePumpKqueue::Mode>(mode), 715 controller, delegate); 716 } 717 718 bool MessageLoopForIO::WatchMachReceivePort(mach_port_t port, 719 MachPortWatchController* controller, 720 MachPortWatcher* delegate) { 721 return pump_kqueue()->WatchMachReceivePort(port, controller, delegate); 722 } 723 724 #else 725 726 bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, Mode mode, 727 FileDescriptorWatcher* controller, 728 Watcher* delegate) { 729 return pump_libevent()->WatchFileDescriptor( 730 fd, persistent, static_cast<base::MessagePumpLibevent::Mode>(mode), 731 controller, delegate); 732 } 733 734 #endif