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