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