message_loop.cc revision c7f5f8508d98d5952d42ed7648c2a8f30a4da156
1// Copyright (c) 2009 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.h"
6
7#include <algorithm>
8
9#include "base/compiler_specific.h"
10#include "base/lazy_instance.h"
11#include "base/logging.h"
12#include "base/message_pump_default.h"
13#include "base/string_util.h"
14#include "base/thread_local.h"
15
16#if defined(OS_MACOSX)
17#include "base/message_pump_mac.h"
18#endif
19#if defined(OS_POSIX)
20#include "base/message_pump_libevent.h"
21#include "base/third_party/valgrind/valgrind.h"
22#endif
23#if defined(OS_POSIX) && !defined(OS_MACOSX)
24#include "base/message_pump_glib.h"
25#endif
26
27using base::Time;
28using base::TimeDelta;
29
30// A lazily created thread local storage for quick access to a thread's message
31// loop, if one exists.  This should be safe and free of static constructors.
32static base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr(
33    base::LINKER_INITIALIZED);
34
35//------------------------------------------------------------------------------
36
37// Logical events for Histogram profiling. Run with -message-loop-histogrammer
38// to get an accounting of messages and actions taken on each thread.
39static const int kTaskRunEvent = 0x1;
40static const int kTimerEvent = 0x2;
41
42// Provide range of message IDs for use in histogramming and debug display.
43static const int kLeastNonZeroMessageId = 1;
44static const int kMaxMessageId = 1099;
45static const int kNumberOfDistinctMessagesDisplayed = 1100;
46
47//------------------------------------------------------------------------------
48
49#if defined(OS_WIN)
50
51// Upon a SEH exception in this thread, it restores the original unhandled
52// exception filter.
53static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
54  ::SetUnhandledExceptionFilter(old_filter);
55  return EXCEPTION_CONTINUE_SEARCH;
56}
57
58// Retrieves a pointer to the current unhandled exception filter. There
59// is no standalone getter method.
60static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
61  LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
62  top_filter = ::SetUnhandledExceptionFilter(0);
63  ::SetUnhandledExceptionFilter(top_filter);
64  return top_filter;
65}
66
67#endif  // defined(OS_WIN)
68
69//------------------------------------------------------------------------------
70
71// static
72MessageLoop* MessageLoop::current() {
73  // TODO(darin): sadly, we cannot enable this yet since people call us even
74  // when they have no intention of using us.
75  // DCHECK(loop) << "Ouch, did you forget to initialize me?";
76  return lazy_tls_ptr.Pointer()->Get();
77}
78
79MessageLoop::MessageLoop(Type type)
80    : type_(type),
81      nestable_tasks_allowed_(true),
82      exception_restoration_(false),
83      state_(NULL),
84      next_sequence_num_(0) {
85  DCHECK(!current()) << "should only have one message loop per thread";
86  lazy_tls_ptr.Pointer()->Set(this);
87
88#if defined(OS_WIN)
89  // TODO(rvargas): Get rid of the OS guards.
90  if (type_ == TYPE_DEFAULT) {
91    pump_ = new base::MessagePumpDefault();
92  } else if (type_ == TYPE_IO) {
93    pump_ = new base::MessagePumpForIO();
94  } else {
95    DCHECK(type_ == TYPE_UI);
96    pump_ = new base::MessagePumpForUI();
97  }
98#elif defined(OS_POSIX)
99  if (type_ == TYPE_UI) {
100#if defined(OS_MACOSX)
101    pump_ = base::MessagePumpMac::Create();
102#else
103    pump_ = new base::MessagePumpForUI();
104#endif
105  } else if (type_ == TYPE_IO) {
106    pump_ = new base::MessagePumpLibevent();
107  } else {
108    pump_ = new base::MessagePumpDefault();
109  }
110#endif  // OS_POSIX
111}
112
113MessageLoop::~MessageLoop() {
114  DCHECK(this == current());
115
116  // Let interested parties have one last shot at accessing this.
117  FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
118                    WillDestroyCurrentMessageLoop());
119
120  DCHECK(!state_);
121
122  // Clean up any unprocessed tasks, but take care: deleting a task could
123  // result in the addition of more tasks (e.g., via DeleteSoon).  We set a
124  // limit on the number of times we will allow a deleted task to generate more
125  // tasks.  Normally, we should only pass through this loop once or twice.  If
126  // we end up hitting the loop limit, then it is probably due to one task that
127  // is being stubborn.  Inspect the queues to see who is left.
128  bool did_work;
129  for (int i = 0; i < 100; ++i) {
130    DeletePendingTasks();
131    ReloadWorkQueue();
132    // If we end up with empty queues, then break out of the loop.
133    did_work = DeletePendingTasks();
134    if (!did_work)
135      break;
136  }
137  DCHECK(!did_work);
138
139  // OK, now make it so that no one can find us.
140  lazy_tls_ptr.Pointer()->Set(NULL);
141}
142
143void MessageLoop::AddDestructionObserver(DestructionObserver *obs) {
144  DCHECK(this == current());
145  destruction_observers_.AddObserver(obs);
146}
147
148void MessageLoop::RemoveDestructionObserver(DestructionObserver *obs) {
149  DCHECK(this == current());
150  destruction_observers_.RemoveObserver(obs);
151}
152
153void MessageLoop::Run() {
154  AutoRunState save_state(this);
155  RunHandler();
156}
157
158void MessageLoop::RunAllPending() {
159  AutoRunState save_state(this);
160  state_->quit_received = true;  // Means run until we would otherwise block.
161  RunHandler();
162}
163
164// Runs the loop in two different SEH modes:
165// enable_SEH_restoration_ = false : any unhandled exception goes to the last
166// one that calls SetUnhandledExceptionFilter().
167// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
168// that was existed before the loop was run.
169void MessageLoop::RunHandler() {
170#if defined(OS_WIN)
171  if (exception_restoration_) {
172    RunInternalInSEHFrame();
173    return;
174  }
175#endif
176
177  RunInternal();
178}
179//------------------------------------------------------------------------------
180#if defined(OS_WIN)
181__declspec(noinline) void MessageLoop::RunInternalInSEHFrame() {
182  LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
183  __try {
184    RunInternal();
185  } __except(SEHFilter(current_filter)) {
186  }
187  return;
188}
189#endif
190//------------------------------------------------------------------------------
191
192void MessageLoop::RunInternal() {
193  DCHECK(this == current());
194
195  StartHistogrammer();
196
197#if !defined(OS_MACOSX)
198  if (state_->dispatcher && type() == TYPE_UI) {
199    static_cast<base::MessagePumpForUI*>(pump_.get())->
200        RunWithDispatcher(this, state_->dispatcher);
201    return;
202  }
203#endif
204
205  pump_->Run(this);
206}
207
208//------------------------------------------------------------------------------
209// Wrapper functions for use in above message loop framework.
210
211bool MessageLoop::ProcessNextDelayedNonNestableTask() {
212  if (state_->run_depth != 1)
213    return false;
214
215  if (deferred_non_nestable_work_queue_.empty())
216    return false;
217
218  Task* task = deferred_non_nestable_work_queue_.front().task;
219  deferred_non_nestable_work_queue_.pop();
220
221  RunTask(task);
222  return true;
223}
224
225//------------------------------------------------------------------------------
226
227void MessageLoop::Quit() {
228  DCHECK(current() == this);
229  if (state_) {
230    state_->quit_received = true;
231  } else {
232    NOTREACHED() << "Must be inside Run to call Quit";
233  }
234}
235
236void MessageLoop::PostTask(
237    const tracked_objects::Location& from_here, Task* task) {
238  PostTask_Helper(from_here, task, 0, true);
239}
240
241void MessageLoop::PostDelayedTask(
242    const tracked_objects::Location& from_here, Task* task, int64 delay_ms) {
243  PostTask_Helper(from_here, task, delay_ms, true);
244}
245
246void MessageLoop::PostNonNestableTask(
247    const tracked_objects::Location& from_here, Task* task) {
248  PostTask_Helper(from_here, task, 0, false);
249}
250
251void MessageLoop::PostNonNestableDelayedTask(
252    const tracked_objects::Location& from_here, Task* task, int64 delay_ms) {
253  PostTask_Helper(from_here, task, delay_ms, false);
254}
255
256// Possibly called on a background thread!
257void MessageLoop::PostTask_Helper(
258    const tracked_objects::Location& from_here, Task* task, int64 delay_ms,
259    bool nestable) {
260  task->SetBirthPlace(from_here);
261
262  PendingTask pending_task(task, nestable);
263
264  if (delay_ms > 0) {
265    pending_task.delayed_run_time =
266        Time::Now() + TimeDelta::FromMilliseconds(delay_ms);
267  } else {
268    DCHECK_EQ(delay_ms, 0) << "delay should not be negative";
269  }
270
271  // Warning: Don't try to short-circuit, and handle this thread's tasks more
272  // directly, as it could starve handling of foreign threads.  Put every task
273  // into this queue.
274
275  scoped_refptr<base::MessagePump> pump;
276  {
277    AutoLock locked(incoming_queue_lock_);
278
279    bool was_empty = incoming_queue_.empty();
280    incoming_queue_.push(pending_task);
281    if (!was_empty)
282      return;  // Someone else should have started the sub-pump.
283
284    pump = pump_;
285  }
286  // Since the incoming_queue_ may contain a task that destroys this message
287  // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
288  // We use a stack-based reference to the message pump so that we can call
289  // ScheduleWork outside of incoming_queue_lock_.
290
291  pump->ScheduleWork();
292}
293
294void MessageLoop::SetNestableTasksAllowed(bool allowed) {
295  if (nestable_tasks_allowed_ != allowed) {
296    nestable_tasks_allowed_ = allowed;
297    if (!nestable_tasks_allowed_)
298      return;
299    // Start the native pump if we are not already pumping.
300    pump_->ScheduleWork();
301  }
302}
303
304bool MessageLoop::NestableTasksAllowed() const {
305  return nestable_tasks_allowed_;
306}
307
308bool MessageLoop::IsNested() {
309  return state_->run_depth > 1;
310}
311
312//------------------------------------------------------------------------------
313
314void MessageLoop::RunTask(Task* task) {
315  DCHECK(nestable_tasks_allowed_);
316  // Execute the task and assume the worst: It is probably not reentrant.
317  nestable_tasks_allowed_ = false;
318
319  HistogramEvent(kTaskRunEvent);
320  task->Run();
321  delete task;
322
323  nestable_tasks_allowed_ = true;
324}
325
326bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
327  if (pending_task.nestable || state_->run_depth == 1) {
328    RunTask(pending_task.task);
329    // Show that we ran a task (Note: a new one might arrive as a
330    // consequence!).
331    return true;
332  }
333
334  // We couldn't run the task now because we're in a nested message loop
335  // and the task isn't nestable.
336  deferred_non_nestable_work_queue_.push(pending_task);
337  return false;
338}
339
340void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
341  // Move to the delayed work queue.  Initialize the sequence number
342  // before inserting into the delayed_work_queue_.  The sequence number
343  // is used to faciliate FIFO sorting when two tasks have the same
344  // delayed_run_time value.
345  PendingTask new_pending_task(pending_task);
346  new_pending_task.sequence_num = next_sequence_num_++;
347  delayed_work_queue_.push(new_pending_task);
348}
349
350void MessageLoop::ReloadWorkQueue() {
351  // We can improve performance of our loading tasks from incoming_queue_ to
352  // work_queue_ by waiting until the last minute (work_queue_ is empty) to
353  // load.  That reduces the number of locks-per-task significantly when our
354  // queues get large.
355  if (!work_queue_.empty())
356    return;  // Wait till we *really* need to lock and load.
357
358  // Acquire all we can from the inter-thread queue with one lock acquisition.
359  {
360    AutoLock lock(incoming_queue_lock_);
361    if (incoming_queue_.empty())
362      return;
363    incoming_queue_.Swap(&work_queue_);  // Constant time
364    DCHECK(incoming_queue_.empty());
365  }
366}
367
368bool MessageLoop::DeletePendingTasks() {
369  bool did_work = !work_queue_.empty();
370  while (!work_queue_.empty()) {
371    PendingTask pending_task = work_queue_.front();
372    work_queue_.pop();
373    if (!pending_task.delayed_run_time.is_null()) {
374      // We want to delete delayed tasks in the same order in which they would
375      // normally be deleted in case of any funny dependencies between delayed
376      // tasks.
377      AddToDelayedWorkQueue(pending_task);
378    } else {
379      // TODO(darin): Delete all tasks once it is safe to do so.
380      // Until it is totally safe, just do it when running Purify or
381      // Valgrind.
382#if defined(PURIFY)
383      delete pending_task.task;
384#elif defined(OS_POSIX)
385      if (RUNNING_ON_VALGRIND)
386        delete pending_task.task;
387#endif  // defined(OS_POSIX)
388    }
389  }
390  did_work |= !deferred_non_nestable_work_queue_.empty();
391  while (!deferred_non_nestable_work_queue_.empty()) {
392    // TODO(darin): Delete all tasks once it is safe to do so.
393    // Until it is totaly safe, only delete them under Purify and Valgrind.
394    Task* task = NULL;
395#if defined(PURIFY)
396    task = deferred_non_nestable_work_queue_.front().task;
397#elif defined(OS_POSIX)
398    if (RUNNING_ON_VALGRIND)
399      task = deferred_non_nestable_work_queue_.front().task;
400#endif
401    deferred_non_nestable_work_queue_.pop();
402    if (task)
403      delete task;
404  }
405  did_work |= !delayed_work_queue_.empty();
406  while (!delayed_work_queue_.empty()) {
407    Task* task = delayed_work_queue_.top().task;
408    delayed_work_queue_.pop();
409    delete task;
410  }
411  return did_work;
412}
413
414bool MessageLoop::DoWork() {
415  if (!nestable_tasks_allowed_) {
416    // Task can't be executed right now.
417    return false;
418  }
419
420  for (;;) {
421    ReloadWorkQueue();
422    if (work_queue_.empty())
423      break;
424
425    // Execute oldest task.
426    do {
427      PendingTask pending_task = work_queue_.front();
428      work_queue_.pop();
429      if (!pending_task.delayed_run_time.is_null()) {
430        AddToDelayedWorkQueue(pending_task);
431        // If we changed the topmost task, then it is time to re-schedule.
432        if (delayed_work_queue_.top().task == pending_task.task)
433          pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
434      } else {
435        if (DeferOrRunPendingTask(pending_task))
436          return true;
437      }
438    } while (!work_queue_.empty());
439  }
440
441  // Nothing happened.
442  return false;
443}
444
445bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) {
446  if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
447    *next_delayed_work_time = Time();
448    return false;
449  }
450
451  if (delayed_work_queue_.top().delayed_run_time > Time::Now()) {
452    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
453    return false;
454  }
455
456  PendingTask pending_task = delayed_work_queue_.top();
457  delayed_work_queue_.pop();
458
459  if (!delayed_work_queue_.empty())
460    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
461
462  return DeferOrRunPendingTask(pending_task);
463}
464
465bool MessageLoop::DoIdleWork() {
466  if (ProcessNextDelayedNonNestableTask())
467    return true;
468
469  if (state_->quit_received)
470    pump_->Quit();
471
472  return false;
473}
474
475//------------------------------------------------------------------------------
476// MessageLoop::AutoRunState
477
478MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
479  // Make the loop reference us.
480  previous_state_ = loop_->state_;
481  if (previous_state_) {
482    run_depth = previous_state_->run_depth + 1;
483  } else {
484    run_depth = 1;
485  }
486  loop_->state_ = this;
487
488  // Initialize the other fields:
489  quit_received = false;
490#if !defined(OS_MACOSX)
491  dispatcher = NULL;
492#endif
493}
494
495MessageLoop::AutoRunState::~AutoRunState() {
496  loop_->state_ = previous_state_;
497}
498
499//------------------------------------------------------------------------------
500// MessageLoop::PendingTask
501
502bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
503  // Since the top of a priority queue is defined as the "greatest" element, we
504  // need to invert the comparison here.  We want the smaller time to be at the
505  // top of the heap.
506
507  if (delayed_run_time < other.delayed_run_time)
508    return false;
509
510  if (delayed_run_time > other.delayed_run_time)
511    return true;
512
513  // If the times happen to match, then we use the sequence number to decide.
514  // Compare the difference to support integer roll-over.
515  return (sequence_num - other.sequence_num) > 0;
516}
517
518//------------------------------------------------------------------------------
519// Method and data for histogramming events and actions taken by each instance
520// on each thread.
521
522// static
523bool MessageLoop::enable_histogrammer_ = false;
524
525// static
526void MessageLoop::EnableHistogrammer(bool enable) {
527  enable_histogrammer_ = enable;
528}
529
530void MessageLoop::StartHistogrammer() {
531  if (enable_histogrammer_ && !message_histogram_.get()
532      && StatisticsRecorder::WasStarted()) {
533    DCHECK(!thread_name_.empty());
534    message_histogram_ = LinearHistogram::FactoryGet("MsgLoop:" + thread_name_,
535        kLeastNonZeroMessageId, kMaxMessageId,
536        kNumberOfDistinctMessagesDisplayed,
537        message_histogram_->kHexRangePrintingFlag);
538    message_histogram_->SetRangeDescriptions(event_descriptions_);
539  }
540}
541
542void MessageLoop::HistogramEvent(int event) {
543  if (message_histogram_.get())
544    message_histogram_->Add(event);
545}
546
547// Provide a macro that takes an expression (such as a constant, or macro
548// constant) and creates a pair to initalize an array of pairs.  In this case,
549// our pair consists of the expressions value, and the "stringized" version
550// of the expression (i.e., the exrpression put in quotes).  For example, if
551// we have:
552//    #define FOO 2
553//    #define BAR 5
554// then the following:
555//    VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
556// will expand to:
557//   {7, "FOO + BAR"}
558// We use the resulting array as an argument to our histogram, which reads the
559// number as a bucket identifier, and proceeds to use the corresponding name
560// in the pair (i.e., the quoted string) when printing out a histogram.
561#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
562
563// static
564const LinearHistogram::DescriptionPair MessageLoop::event_descriptions_[] = {
565  // Provide some pretty print capability in our histogram for our internal
566  // messages.
567
568  // A few events we handle (kindred to messages), and used to profile actions.
569  VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
570  VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
571
572  {-1, NULL}  // The list must be null terminated, per API to histogram.
573};
574
575//------------------------------------------------------------------------------
576// MessageLoopForUI
577
578#if defined(OS_WIN)
579void MessageLoopForUI::WillProcessMessage(const MSG& message) {
580  pump_win()->WillProcessMessage(message);
581}
582void MessageLoopForUI::DidProcessMessage(const MSG& message) {
583  pump_win()->DidProcessMessage(message);
584}
585void MessageLoopForUI::PumpOutPendingPaintMessages() {
586  pump_ui()->PumpOutPendingPaintMessages();
587}
588
589#endif  // defined(OS_WIN)
590
591#if !defined(OS_MACOSX)
592void MessageLoopForUI::AddObserver(Observer* observer) {
593  pump_ui()->AddObserver(observer);
594}
595
596void MessageLoopForUI::RemoveObserver(Observer* observer) {
597  pump_ui()->RemoveObserver(observer);
598}
599
600void MessageLoopForUI::Run(Dispatcher* dispatcher) {
601  AutoRunState save_state(this);
602  state_->dispatcher = dispatcher;
603  RunHandler();
604}
605#endif  // !defined(OS_MACOSX)
606
607//------------------------------------------------------------------------------
608// MessageLoopForIO
609
610#if defined(OS_WIN)
611
612void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
613  pump_io()->RegisterIOHandler(file, handler);
614}
615
616bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
617  return pump_io()->WaitForIOCompletion(timeout, filter);
618}
619
620#elif defined(OS_POSIX)
621
622bool MessageLoopForIO::WatchFileDescriptor(int fd,
623                                           bool persistent,
624                                           Mode mode,
625                                           FileDescriptorWatcher *controller,
626                                           Watcher *delegate) {
627  return pump_libevent()->WatchFileDescriptor(
628      fd,
629      persistent,
630      static_cast<base::MessagePumpLibevent::Mode>(mode),
631      controller,
632      delegate);
633}
634
635#endif
636