LCOV - code coverage report
Current view: top level - ipc/chromium/src/base - message_loop.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 186 241 77.2 %
Date: 2017-07-14 16:53:18 Functions: 35 45 77.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13