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
41namespace base {
42
43namespace {
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.
47LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky 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.
52const int kTaskRunEvent = 0x1;
53const int kTimerEvent = 0x2;
54
55// Provide range of message IDs for use in histogramming and debug display.
56const int kLeastNonZeroMessageId = 1;
57const int kMaxMessageId = 1099;
58const 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
76const 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
87bool enable_histogrammer_ = false;
88
89MessageLoop::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.
93bool 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.
109static 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.
116static 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
127MessageLoop::TaskObserver::TaskObserver() {
128}
129
130MessageLoop::TaskObserver::~TaskObserver() {
131}
132
133MessageLoop::DestructionObserver::~DestructionObserver() {
134}
135
136//------------------------------------------------------------------------------
137
138MessageLoop::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  Init();
148
149  pump_.reset(CreateMessagePumpForType(type));
150}
151
152MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
153    : pump_(pump.Pass()),
154      type_(TYPE_CUSTOM),
155      exception_restoration_(false),
156      nestable_tasks_allowed_(true),
157#if defined(OS_WIN)
158      os_modal_loop_(false),
159#endif  // OS_WIN
160      message_histogram_(NULL),
161      run_loop_(NULL) {
162  DCHECK(pump_.get());
163  Init();
164}
165
166MessageLoop::~MessageLoop() {
167  DCHECK_EQ(this, current());
168
169  DCHECK(!run_loop_);
170
171  // Clean up any unprocessed tasks, but take care: deleting a task could
172  // result in the addition of more tasks (e.g., via DeleteSoon).  We set a
173  // limit on the number of times we will allow a deleted task to generate more
174  // tasks.  Normally, we should only pass through this loop once or twice.  If
175  // we end up hitting the loop limit, then it is probably due to one task that
176  // is being stubborn.  Inspect the queues to see who is left.
177  bool did_work;
178  for (int i = 0; i < 100; ++i) {
179    DeletePendingTasks();
180    ReloadWorkQueue();
181    // If we end up with empty queues, then break out of the loop.
182    did_work = DeletePendingTasks();
183    if (!did_work)
184      break;
185  }
186  DCHECK(!did_work);
187
188  // Let interested parties have one last shot at accessing this.
189  FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
190                    WillDestroyCurrentMessageLoop());
191
192  thread_task_runner_handle_.reset();
193
194  // Tell the incoming queue that we are dying.
195  incoming_task_queue_->WillDestroyCurrentMessageLoop();
196  incoming_task_queue_ = NULL;
197  message_loop_proxy_ = NULL;
198
199  // OK, now make it so that no one can find us.
200  lazy_tls_ptr.Pointer()->Set(NULL);
201}
202
203// static
204MessageLoop* MessageLoop::current() {
205  // TODO(darin): sadly, we cannot enable this yet since people call us even
206  // when they have no intention of using us.
207  // DCHECK(loop) << "Ouch, did you forget to initialize me?";
208  return lazy_tls_ptr.Pointer()->Get();
209}
210
211// static
212void MessageLoop::EnableHistogrammer(bool enable) {
213  enable_histogrammer_ = enable;
214}
215
216// static
217bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
218  if (message_pump_for_ui_factory_)
219    return false;
220
221  message_pump_for_ui_factory_ = factory;
222  return true;
223}
224
225// static
226MessagePump* MessageLoop::CreateMessagePumpForType(Type type) {
227// TODO(rvargas): Get rid of the OS guards.
228#if defined(OS_WIN)
229#define MESSAGE_PUMP_UI new MessagePumpForUI()
230#define MESSAGE_PUMP_IO new MessagePumpForIO()
231#elif defined(OS_IOS)
232#define MESSAGE_PUMP_UI MessagePumpMac::Create()
233#define MESSAGE_PUMP_IO new MessagePumpIOSForIO()
234#elif defined(OS_MACOSX)
235#define MESSAGE_PUMP_UI MessagePumpMac::Create()
236#define MESSAGE_PUMP_IO new MessagePumpLibevent()
237#elif defined(OS_NACL)
238// Currently NaCl doesn't have a UI MessageLoop.
239// TODO(abarth): Figure out if we need this.
240#define MESSAGE_PUMP_UI NULL
241// ipc_channel_nacl.cc uses a worker thread to do socket reads currently, and
242// doesn't require extra support for watching file descriptors.
243#define MESSAGE_PUMP_IO new MessagePumpDefault()
244#elif defined(OS_POSIX)  // POSIX but not MACOSX.
245#define MESSAGE_PUMP_UI new MessagePumpForUI()
246#define MESSAGE_PUMP_IO new MessagePumpLibevent()
247#else
248#error Not implemented
249#endif
250
251  if (type == MessageLoop::TYPE_UI) {
252    if (message_pump_for_ui_factory_)
253      return message_pump_for_ui_factory_();
254    return MESSAGE_PUMP_UI;
255  }
256  if (type == MessageLoop::TYPE_IO)
257    return MESSAGE_PUMP_IO;
258#if defined(TOOLKIT_GTK)
259  if (type == MessageLoop::TYPE_GPU)
260    return new MessagePumpX11();
261#endif
262#if defined(OS_ANDROID)
263  if (type == MessageLoop::TYPE_JAVA)
264    return MESSAGE_PUMP_UI;
265#endif
266  DCHECK_EQ(MessageLoop::TYPE_DEFAULT, type);
267  return new MessagePumpDefault();
268}
269
270void MessageLoop::AddDestructionObserver(
271    DestructionObserver* destruction_observer) {
272  DCHECK_EQ(this, current());
273  destruction_observers_.AddObserver(destruction_observer);
274}
275
276void MessageLoop::RemoveDestructionObserver(
277    DestructionObserver* destruction_observer) {
278  DCHECK_EQ(this, current());
279  destruction_observers_.RemoveObserver(destruction_observer);
280}
281
282void MessageLoop::PostTask(
283    const tracked_objects::Location& from_here,
284    const Closure& task) {
285  DCHECK(!task.is_null()) << from_here.ToString();
286  incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true);
287}
288
289bool MessageLoop::TryPostTask(
290    const tracked_objects::Location& from_here,
291    const Closure& task) {
292  DCHECK(!task.is_null()) << from_here.ToString();
293  return incoming_task_queue_->TryAddToIncomingQueue(from_here, task);
294}
295
296void MessageLoop::PostDelayedTask(
297    const tracked_objects::Location& from_here,
298    const Closure& task,
299    TimeDelta delay) {
300  DCHECK(!task.is_null()) << from_here.ToString();
301  incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true);
302}
303
304void MessageLoop::PostNonNestableTask(
305    const tracked_objects::Location& from_here,
306    const Closure& task) {
307  DCHECK(!task.is_null()) << from_here.ToString();
308  incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false);
309}
310
311void MessageLoop::PostNonNestableDelayedTask(
312    const tracked_objects::Location& from_here,
313    const Closure& task,
314    TimeDelta delay) {
315  DCHECK(!task.is_null()) << from_here.ToString();
316  incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false);
317}
318
319void MessageLoop::Run() {
320  RunLoop run_loop;
321  run_loop.Run();
322}
323
324void MessageLoop::RunUntilIdle() {
325  RunLoop run_loop;
326  run_loop.RunUntilIdle();
327}
328
329void MessageLoop::QuitWhenIdle() {
330  DCHECK_EQ(this, current());
331  if (run_loop_) {
332    run_loop_->quit_when_idle_received_ = true;
333  } else {
334    NOTREACHED() << "Must be inside Run to call Quit";
335  }
336}
337
338void MessageLoop::QuitNow() {
339  DCHECK_EQ(this, current());
340  if (run_loop_) {
341    pump_->Quit();
342  } else {
343    NOTREACHED() << "Must be inside Run to call Quit";
344  }
345}
346
347bool MessageLoop::IsType(Type type) const {
348  return type_ == type;
349}
350
351static void QuitCurrentWhenIdle() {
352  MessageLoop::current()->QuitWhenIdle();
353}
354
355// static
356Closure MessageLoop::QuitWhenIdleClosure() {
357  return Bind(&QuitCurrentWhenIdle);
358}
359
360void MessageLoop::SetNestableTasksAllowed(bool allowed) {
361  if (allowed) {
362    // Kick the native pump just in case we enter a OS-driven nested message
363    // loop.
364    pump_->ScheduleWork();
365  }
366  nestable_tasks_allowed_ = allowed;
367}
368
369bool MessageLoop::NestableTasksAllowed() const {
370  return nestable_tasks_allowed_;
371}
372
373bool MessageLoop::IsNested() {
374  return run_loop_->run_depth_ > 1;
375}
376
377void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
378  DCHECK_EQ(this, current());
379  task_observers_.AddObserver(task_observer);
380}
381
382void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
383  DCHECK_EQ(this, current());
384  task_observers_.RemoveObserver(task_observer);
385}
386
387bool MessageLoop::is_running() const {
388  DCHECK_EQ(this, current());
389  return run_loop_ != NULL;
390}
391
392bool MessageLoop::IsHighResolutionTimerEnabledForTesting() {
393  return incoming_task_queue_->IsHighResolutionTimerEnabledForTesting();
394}
395
396bool MessageLoop::IsIdleForTesting() {
397  // We only check the imcoming queue|, since we don't want to lock the work
398  // queue.
399  return incoming_task_queue_->IsIdleForTesting();
400}
401
402void MessageLoop::LockWaitUnLockForTesting(WaitableEvent* caller_wait,
403                                           WaitableEvent* caller_signal) {
404  incoming_task_queue_->LockWaitUnLockForTesting(caller_wait, caller_signal);
405}
406
407//------------------------------------------------------------------------------
408
409void MessageLoop::Init() {
410  DCHECK(!current()) << "should only have one message loop per thread";
411  lazy_tls_ptr.Pointer()->Set(this);
412
413  incoming_task_queue_ = new internal::IncomingTaskQueue(this);
414  message_loop_proxy_ =
415      new internal::MessageLoopProxyImpl(incoming_task_queue_);
416  thread_task_runner_handle_.reset(
417      new ThreadTaskRunnerHandle(message_loop_proxy_));
418}
419
420// Runs the loop in two different SEH modes:
421// enable_SEH_restoration_ = false : any unhandled exception goes to the last
422// one that calls SetUnhandledExceptionFilter().
423// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
424// that was existed before the loop was run.
425void MessageLoop::RunHandler() {
426#if defined(OS_WIN)
427  if (exception_restoration_) {
428    RunInternalInSEHFrame();
429    return;
430  }
431#endif
432
433  RunInternal();
434}
435
436#if defined(OS_WIN)
437__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() {
438  LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
439  __try {
440    RunInternal();
441  } __except(SEHFilter(current_filter)) {
442  }
443  return;
444}
445#endif
446
447void MessageLoop::RunInternal() {
448  DCHECK_EQ(this, current());
449
450  StartHistogrammer();
451
452#if !defined(OS_MACOSX) && !defined(OS_ANDROID) && \
453    !defined(USE_GTK_MESSAGE_PUMP)
454  if (run_loop_->dispatcher_ && type() == TYPE_UI) {
455    static_cast<MessagePumpForUI*>(pump_.get())->
456        RunWithDispatcher(this, run_loop_->dispatcher_);
457    return;
458  }
459#endif
460
461  pump_->Run(this);
462}
463
464bool MessageLoop::ProcessNextDelayedNonNestableTask() {
465  if (run_loop_->run_depth_ != 1)
466    return false;
467
468  if (deferred_non_nestable_work_queue_.empty())
469    return false;
470
471  PendingTask pending_task = deferred_non_nestable_work_queue_.front();
472  deferred_non_nestable_work_queue_.pop();
473
474  RunTask(pending_task);
475  return true;
476}
477
478void MessageLoop::RunTask(const PendingTask& pending_task) {
479  tracked_objects::TrackedTime start_time =
480      tracked_objects::ThreadData::NowForStartOfRun(pending_task.birth_tally);
481
482  TRACE_EVENT_FLOW_END1("task", "MessageLoop::PostTask",
483      TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
484      "queue_duration",
485      (start_time - pending_task.EffectiveTimePosted()).InMilliseconds());
486  // When tracing memory for posted tasks it's more valuable to attribute the
487  // memory allocations to the source function than generically to "RunTask".
488  TRACE_EVENT_WITH_MEMORY_TAG2(
489      "task", "MessageLoop::RunTask",
490      pending_task.posted_from.function_name(),  // Name for memory tracking.
491      "src_file", pending_task.posted_from.file_name(),
492      "src_func", pending_task.posted_from.function_name());
493
494  DCHECK(nestable_tasks_allowed_);
495  // Execute the task and assume the worst: It is probably not reentrant.
496  nestable_tasks_allowed_ = false;
497
498  // Before running the task, store the program counter where it was posted
499  // and deliberately alias it to ensure it is on the stack if the task
500  // crashes. Be careful not to assume that the variable itself will have the
501  // expected value when displayed by the optimizer in an optimized build.
502  // Look at a memory dump of the stack.
503  const void* program_counter =
504      pending_task.posted_from.program_counter();
505  debug::Alias(&program_counter);
506
507  HistogramEvent(kTaskRunEvent);
508
509  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
510                    WillProcessTask(pending_task));
511  pending_task.task.Run();
512  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
513                    DidProcessTask(pending_task));
514
515  tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(pending_task,
516      start_time, tracked_objects::ThreadData::NowForEndOfRun());
517
518  nestable_tasks_allowed_ = true;
519}
520
521bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
522  if (pending_task.nestable || run_loop_->run_depth_ == 1) {
523    RunTask(pending_task);
524    // Show that we ran a task (Note: a new one might arrive as a
525    // consequence!).
526    return true;
527  }
528
529  // We couldn't run the task now because we're in a nested message loop
530  // and the task isn't nestable.
531  deferred_non_nestable_work_queue_.push(pending_task);
532  return false;
533}
534
535void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
536  // Move to the delayed work queue.
537  delayed_work_queue_.push(pending_task);
538}
539
540bool MessageLoop::DeletePendingTasks() {
541  bool did_work = !work_queue_.empty();
542  while (!work_queue_.empty()) {
543    PendingTask pending_task = work_queue_.front();
544    work_queue_.pop();
545    if (!pending_task.delayed_run_time.is_null()) {
546      // We want to delete delayed tasks in the same order in which they would
547      // normally be deleted in case of any funny dependencies between delayed
548      // tasks.
549      AddToDelayedWorkQueue(pending_task);
550    }
551  }
552  did_work |= !deferred_non_nestable_work_queue_.empty();
553  while (!deferred_non_nestable_work_queue_.empty()) {
554    deferred_non_nestable_work_queue_.pop();
555  }
556  did_work |= !delayed_work_queue_.empty();
557
558  // Historically, we always delete the task regardless of valgrind status. It's
559  // not completely clear why we want to leak them in the loops above.  This
560  // code is replicating legacy behavior, and should not be considered
561  // absolutely "correct" behavior.  See TODO above about deleting all tasks
562  // when it's safe.
563  while (!delayed_work_queue_.empty()) {
564    delayed_work_queue_.pop();
565  }
566  return did_work;
567}
568
569uint64 MessageLoop::GetTaskTraceID(const PendingTask& task) {
570  return (static_cast<uint64>(task.sequence_num) << 32) |
571         ((static_cast<uint64>(reinterpret_cast<intptr_t>(this)) << 32) >> 32);
572}
573
574void MessageLoop::ReloadWorkQueue() {
575  // We can improve performance of our loading tasks from the incoming queue to
576  // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to
577  // load. That reduces the number of locks-per-task significantly when our
578  // queues get large.
579  if (work_queue_.empty())
580    incoming_task_queue_->ReloadWorkQueue(&work_queue_);
581}
582
583void MessageLoop::ScheduleWork(bool was_empty) {
584  // The Android UI message loop needs to get notified each time
585  // a task is added to the incoming queue.
586  if (was_empty || AlwaysNotifyPump(type_))
587    pump_->ScheduleWork();
588}
589
590//------------------------------------------------------------------------------
591// Method and data for histogramming events and actions taken by each instance
592// on each thread.
593
594void MessageLoop::StartHistogrammer() {
595#if !defined(OS_NACL)  // NaCl build has no metrics code.
596  if (enable_histogrammer_ && !message_histogram_
597      && StatisticsRecorder::IsActive()) {
598    DCHECK(!thread_name_.empty());
599    message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription(
600        "MsgLoop:" + thread_name_,
601        kLeastNonZeroMessageId, kMaxMessageId,
602        kNumberOfDistinctMessagesDisplayed,
603        message_histogram_->kHexRangePrintingFlag,
604        event_descriptions_);
605  }
606#endif
607}
608
609void MessageLoop::HistogramEvent(int event) {
610#if !defined(OS_NACL)
611  if (message_histogram_)
612    message_histogram_->Add(event);
613#endif
614}
615
616bool MessageLoop::DoWork() {
617  if (!nestable_tasks_allowed_) {
618    // Task can't be executed right now.
619    return false;
620  }
621
622  for (;;) {
623    ReloadWorkQueue();
624    if (work_queue_.empty())
625      break;
626
627    // Execute oldest task.
628    do {
629      PendingTask pending_task = work_queue_.front();
630      work_queue_.pop();
631      if (!pending_task.delayed_run_time.is_null()) {
632        AddToDelayedWorkQueue(pending_task);
633        // If we changed the topmost task, then it is time to reschedule.
634        if (delayed_work_queue_.top().task.Equals(pending_task.task))
635          pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
636      } else {
637        if (DeferOrRunPendingTask(pending_task))
638          return true;
639      }
640    } while (!work_queue_.empty());
641  }
642
643  // Nothing happened.
644  return false;
645}
646
647bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
648  if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
649    recent_time_ = *next_delayed_work_time = TimeTicks();
650    return false;
651  }
652
653  // When we "fall behind," there will be a lot of tasks in the delayed work
654  // queue that are ready to run.  To increase efficiency when we fall behind,
655  // we will only call Time::Now() intermittently, and then process all tasks
656  // that are ready to run before calling it again.  As a result, the more we
657  // fall behind (and have a lot of ready-to-run delayed tasks), the more
658  // efficient we'll be at handling the tasks.
659
660  TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
661  if (next_run_time > recent_time_) {
662    recent_time_ = TimeTicks::Now();  // Get a better view of Now();
663    if (next_run_time > recent_time_) {
664      *next_delayed_work_time = next_run_time;
665      return false;
666    }
667  }
668
669  PendingTask pending_task = delayed_work_queue_.top();
670  delayed_work_queue_.pop();
671
672  if (!delayed_work_queue_.empty())
673    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
674
675  return DeferOrRunPendingTask(pending_task);
676}
677
678bool MessageLoop::DoIdleWork() {
679  if (ProcessNextDelayedNonNestableTask())
680    return true;
681
682  if (run_loop_->quit_when_idle_received_)
683    pump_->Quit();
684
685  return false;
686}
687
688void MessageLoop::GetQueueingInformation(size_t* queue_size,
689                                         TimeDelta* queueing_delay) {
690  *queue_size = work_queue_.size();
691  if (*queue_size == 0) {
692    *queueing_delay = TimeDelta();
693    return;
694  }
695
696  const PendingTask& next_to_run = work_queue_.front();
697  tracked_objects::Duration duration =
698      tracked_objects::TrackedTime::Now() - next_to_run.EffectiveTimePosted();
699  *queueing_delay = TimeDelta::FromMilliseconds(duration.InMilliseconds());
700}
701
702void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
703                                     void(*deleter)(const void*),
704                                     const void* object) {
705  PostNonNestableTask(from_here, Bind(deleter, object));
706}
707
708void MessageLoop::ReleaseSoonInternal(
709    const tracked_objects::Location& from_here,
710    void(*releaser)(const void*),
711    const void* object) {
712  PostNonNestableTask(from_here, Bind(releaser, object));
713}
714
715//------------------------------------------------------------------------------
716// MessageLoopForUI
717
718#if defined(OS_ANDROID)
719void MessageLoopForUI::Start() {
720  // No Histogram support for UI message loop as it is managed by Java side
721  static_cast<MessagePumpForUI*>(pump_.get())->Start(this);
722}
723#endif
724
725#if defined(OS_IOS)
726void MessageLoopForUI::Attach() {
727  static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this);
728}
729#endif
730
731#if !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
732void MessageLoopForUI::AddObserver(Observer* observer) {
733  pump_ui()->AddObserver(observer);
734}
735
736void MessageLoopForUI::RemoveObserver(Observer* observer) {
737  pump_ui()->RemoveObserver(observer);
738}
739
740#endif  //  !defined(OS_MACOSX) && !defined(OS_NACL) && !defined(OS_ANDROID)
741
742//------------------------------------------------------------------------------
743// MessageLoopForIO
744
745#if defined(OS_WIN)
746
747void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
748  pump_io()->RegisterIOHandler(file, handler);
749}
750
751bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) {
752  return pump_io()->RegisterJobObject(job, handler);
753}
754
755bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
756  return pump_io()->WaitForIOCompletion(timeout, filter);
757}
758
759#elif defined(OS_IOS)
760
761bool MessageLoopForIO::WatchFileDescriptor(int fd,
762                                           bool persistent,
763                                           Mode mode,
764                                           FileDescriptorWatcher *controller,
765                                           Watcher *delegate) {
766  return pump_io()->WatchFileDescriptor(
767      fd,
768      persistent,
769      mode,
770      controller,
771      delegate);
772}
773
774#elif defined(OS_POSIX) && !defined(OS_NACL)
775
776bool MessageLoopForIO::WatchFileDescriptor(int fd,
777                                           bool persistent,
778                                           Mode mode,
779                                           FileDescriptorWatcher *controller,
780                                           Watcher *delegate) {
781  return pump_libevent()->WatchFileDescriptor(
782      fd,
783      persistent,
784      mode,
785      controller,
786      delegate);
787}
788
789#endif
790
791}  // namespace base
792