Implement MessageLoopForUI using GLib.  This gets some exercise from
base_unittest.

BUG=1319

Review URL: http://codereview.chromium.org/4261

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2834 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 8fc3a4815737707de36239119a3d3c648b826e2f
diff --git a/base/SConscript b/base/SConscript
index 939ab6e..41693a5 100644
--- a/base/SConscript
+++ b/base/SConscript
@@ -168,6 +168,7 @@
       'base_paths_linux.cc',
       'file_util_linux.cc',
       'hmac_nss.cc',
+      'message_pump_glib.cc',
       'nss_init.cc',
       'sys_string_conversions_linux.cc',
       'worker_pool.cc',
@@ -351,4 +352,3 @@
 
 # Since run_all_perftests supplies a main, we cannot have it in base.lib
 env_tests.StaticObject('run_all_perftests.cc')
-
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 60a8ce5..348648f 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -19,6 +19,9 @@
 #if defined(OS_POSIX)
 #include "base/message_pump_libevent.h"
 #endif
+#if defined(OS_LINUX)
+#include "base/message_pump_glib.h"
+#endif
 
 // A lazily created thread local storage for quick access to a thread's message
 // loop, if one exists.  This should be safe and free of static constructors.
@@ -89,18 +92,17 @@
     pump_ = new base::MessagePumpForUI();
   }
 #elif defined(OS_POSIX)
-#if defined(OS_MACOSX)
   if (type_ == TYPE_UI) {
+#if defined(OS_MACOSX)
     pump_ = base::MessagePumpMac::Create();
-  } else
-#endif  // OS_MACOSX
-  if (type_ == TYPE_IO) {
+#elif defined(OS_LINUX)
+    pump_ = new base::MessagePumpForUI();
+#endif  // OS_LINUX
+  } else if (type_ == TYPE_IO) {
     pump_ = new base::MessagePumpLibevent();
   } else {
     pump_ = new base::MessagePumpDefault();
   }
-#else  // OS_POSIX
-  pump_ = new base::MessagePumpDefault();
 #endif  // OS_POSIX
 }
 
diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc
new file mode 100644
index 0000000..603c80e
--- /dev/null
+++ b/base/message_pump_glib.cc
@@ -0,0 +1,304 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_glib.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+
+namespace base {
+
+static const char kWorkScheduled = '\0';
+static const char kDelayedWorkScheduled = '\1';
+
+// I wish these could be const, but g_source_new wants a non-const GSourceFunc
+// pointer.
+
+// static
+GSourceFuncs MessagePumpForUI::WorkSourceFuncs = {
+  WorkSourcePrepare,
+  WorkSourceCheck,
+  WorkSourceDispatch,
+  NULL
+};
+
+// static
+GSourceFuncs MessagePumpForUI::IdleSourceFuncs = {
+  IdleSourcePrepare,
+  IdleSourceCheck,
+  IdleSourceDispatch,
+  NULL
+};
+
+static int GetTimeIntervalMilliseconds(Time from) {
+  if (from.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  double timeout = ceil((from - Time::Now()).InMillisecondsF());
+
+  // If this value is negative, then we need to run delayed work soon.
+  int delay = static_cast<int>(timeout);
+  if (delay < 0)
+    delay = 0;
+
+  return delay;
+}
+
+MessagePumpForUI::MessagePumpForUI()
+    : state_(NULL),
+      context_(g_main_context_default()) {
+  // Create a pipe with a non-blocking read end for use by ScheduleWork to
+  // break us out of a poll.  Create the work source and attach the file
+  // descriptor to it.
+  int pipe_fd[2];
+  CHECK(0 == pipe(pipe_fd)) << "Could not create pipe!";
+  write_fd_work_scheduled_ = pipe_fd[1];
+  read_fd_work_scheduled_ = pipe_fd[0];
+  int flags = fcntl(read_fd_work_scheduled_, F_GETFL, 0);
+  if (-1 == flags)
+    flags = 0;
+  CHECK(0 == fcntl(read_fd_work_scheduled_, F_SETFL, flags | O_NONBLOCK)) <<
+      "Could not set file descriptor to non-blocking!";
+  GPollFD poll_fd;
+  poll_fd.fd = read_fd_work_scheduled_;
+  poll_fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+  work_source_ = AddSource(&WorkSourceFuncs, G_PRIORITY_DEFAULT, &poll_fd);
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+  close(read_fd_work_scheduled_);
+  close(write_fd_work_scheduled_);
+  g_source_destroy(work_source_);
+  g_source_unref(work_source_);
+}
+
+struct ThreadIdTraits {
+  static void New(void* instance) {
+    int* thread_id = static_cast<int*>(instance);
+    *thread_id = PlatformThread::CurrentId();
+  }
+  static void Delete(void* instance) {
+  }
+};
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+  // Make sure we only run this on one thread.  GTK only has one message pump
+  // so we can only have one UI loop per process.
+  static LazyInstance<int, ThreadIdTraits> thread_id(base::LINKER_INITIALIZED);
+  DCHECK(thread_id.Get() == PlatformThread::CurrentId()) <<
+      "Running MessagePumpForUI on two different threads; "
+      "this is unsupported by GLib!";
+
+  RunState state;
+  state.delegate = delegate;
+  state.keep_running = true;
+  // We emulate the behavior of MessagePumpDefault and try to do work at once.
+  state.should_do_work = true;
+  state.should_do_idle_work = false;
+  state.idle_source = NULL;
+
+  RunState* previous_state = state_;
+  state_ = &state;
+
+  while (state.keep_running)
+    g_main_context_iteration(context_, true);
+
+  if (state.idle_source) {
+    // This removes the source from the context and releases GLib's hold on it.
+    g_source_destroy(state.idle_source);
+    // This releases our hold and destroys the source.
+    g_source_unref(state.idle_source);
+  }
+
+  state_ = previous_state;
+}
+
+void MessagePumpForUI::Quit() {
+  DCHECK(state_) << "Quit called outside Run!";
+  state_->keep_running = false;
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  // This can be called on any thread, so we don't want to touch any state
+  // variables as we would then need locks all over.  This ensures that if
+  // we are sleeping in a poll that we will wake up, and we check the pipe
+  // so we know when work was scheduled.
+  CHECK(1 == write(write_fd_work_scheduled_, &kWorkScheduled, 1)) <<
+      "Could not write to pipe!";
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) {
+  delayed_work_time_ = delayed_work_time;
+  // This is an optimization.  Delayed work may not be imminent, we may just
+  // need to update our timeout to poll.  Hence we don't want to go overkill
+  // with kWorkScheduled.
+  CHECK(1 == write(write_fd_work_scheduled_, &kDelayedWorkScheduled, 1)) <<
+      "Could not write to pipe!";
+}
+
+// A brief refresher on GLib:
+//     GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
+// On each iteration of the GLib pump, it calls each source's Prepare function.
+// This function should return TRUE if it wants GLib to call its Dispatch, and
+// FALSE otherwise.  It can also set a timeout in this case for the next time
+// Prepare should be called again (it may be called sooner).
+//     After the Prepare calls, GLib does a poll to check for events from the
+// system.  File descriptors can be attached to the sources.  The poll may block
+// if none of the Prepare calls returned TRUE.  It will block indefinitely, or
+// by the minimum time returned by a source in Prepare.
+//     After the poll, GLib calls Check for each source that returned FALSE
+// from Prepare.  The return value of Check has the same meaning as for Prepare,
+// making Check a second chance to tell GLib we are ready for Dispatch.
+//     Finally, GLib calls Dispatch for each source that is ready.  If Dispatch
+// returns FALSE, GLib will destroy the source.  Dispatch calls may be recursive
+// (i.e., you can call Run from them), but Prepare and Check cannot.
+//     Finalize is called when the source is destroyed.
+
+// static
+gboolean MessagePumpForUI::WorkSourcePrepare(GSource* source,
+                                             gint* timeout_ms) {
+  MessagePumpForUI* self = static_cast<WorkSource*>(source)->self;
+  RunState* state = self->state_;
+
+  if (state->should_do_work) {
+    state->should_do_idle_work = false;
+    *timeout_ms = 0;
+    return TRUE;
+  }
+
+  *timeout_ms = GetTimeIntervalMilliseconds(self->delayed_work_time_);
+
+  state->should_do_idle_work = true;
+  // We want to do idle work right before poll goes to sleep.  Obviously
+  // we are not currently asleep, but we may be about to since we have
+  // no work to do.  If we don't have an idle source ready to go it's
+  // probably because it fired already (or we just started and it hasn't
+  // been added yet) and we should add one for when we are ready.  Note
+  // that this new source will get Prepare called on this current pump
+  // iteration since it gets added at the end of the source list.
+  if (!state->idle_source) {
+    state->idle_source =
+        self->AddSource(&IdleSourceFuncs, G_PRIORITY_DEFAULT_IDLE, NULL);
+  }
+
+  return FALSE;
+}
+
+// static
+gboolean MessagePumpForUI::WorkSourceCheck(GSource* source) {
+  MessagePumpForUI* self = static_cast<WorkSource*>(source)->self;
+  RunState* state = self->state_;
+
+  // Make sure we don't attempt idle work until we are really sure we don't
+  // have other work to do.  We'll know this in the call to Prepare.
+  state->should_do_idle_work = false;
+
+  // Check if ScheduleWork or ScheduleDelayedWork was called.  This is a
+  // non-blocking read.
+  char byte;
+  while (0 < read(self->read_fd_work_scheduled_, &byte, 1)) {
+    // Don't assume we actually have work yet unless the stronger ScheduleWork
+    // was called.
+    if (byte == kWorkScheduled)
+      state->should_do_work = true;
+  }
+
+  if (state->should_do_work)
+    return TRUE;
+
+  if (!self->delayed_work_time_.is_null())
+    return self->delayed_work_time_ <= Time::Now();
+
+  return FALSE;
+}
+
+// static
+gboolean MessagePumpForUI::WorkSourceDispatch(GSource* source,
+                                              GSourceFunc unused_func,
+                                              gpointer unused_data) {
+  MessagePumpForUI* self = static_cast<WorkSource*>(source)->self;
+  RunState* state = self->state_;
+  DCHECK(!state->should_do_idle_work) <<
+      "Idle work should not be flagged while regular work exists.";
+
+  // Note that in this function we never return FALSE.  This source is owned
+  // by GLib and shared by multiple calls to Run.  It will only finally get
+  // destroyed when the loop is destroyed.
+
+  state->should_do_work = state->delegate->DoWork();
+  if (!state->keep_running)
+    return TRUE;
+
+  state->should_do_work |=
+      state->delegate->DoDelayedWork(&self->delayed_work_time_);
+
+  return TRUE;
+}
+
+// static
+gboolean MessagePumpForUI::IdleSourcePrepare(GSource* source,
+                                             gint* timeout_ms) {
+  RunState* state = static_cast<WorkSource*>(source)->self->state_;
+  *timeout_ms = 0;
+  return state->should_do_idle_work;
+}
+
+// static
+gboolean MessagePumpForUI::IdleSourceCheck(GSource* source) {
+  RunState* state = static_cast<WorkSource*>(source)->self->state_;
+  return state->should_do_idle_work;
+}
+
+// static
+gboolean MessagePumpForUI::IdleSourceDispatch(GSource* source,
+                                              GSourceFunc unused_func,
+                                              gpointer unused_data) {
+  RunState* state = static_cast<WorkSource*>(source)->self->state_;
+  // We should not do idle work unless we didn't have other work to do.
+  DCHECK(!state->should_do_work) << "Doing idle work in non-idle time!";
+  state->should_do_idle_work = false;
+  state->should_do_work = state->delegate->DoIdleWork();
+
+  // This is an optimization.  We could always remove ourselves right now,
+  // but we will just get re-added when WorkSourceCheck eventually returns
+  // FALSE.
+  if (!state->should_do_work) {
+    // This is so that when we return FALSE, GLib will not only remove us
+    // from the context, but since it holds the last reference, it will
+    // destroy us as well.
+    g_source_unref(source);
+    state->idle_source = NULL;
+  }
+
+  return state->should_do_work;
+}
+
+GSource* MessagePumpForUI::AddSource(GSourceFuncs* funcs, gint priority,
+                                     GPollFD *optional_poll_fd) {
+  GSource* source = g_source_new(funcs, sizeof(WorkSource));
+
+  // Setting the priority is actually a bit expensive since it causes GLib
+  // to resort an internal list.
+  if (priority != G_PRIORITY_DEFAULT)
+    g_source_set_priority(source, priority);
+
+  // This is needed to allow Run calls inside Dispatch.
+  g_source_set_can_recurse(source, TRUE);
+  static_cast<WorkSource*>(source)->self = this;
+
+  if (optional_poll_fd)
+    g_source_add_poll(source, optional_poll_fd);
+
+  g_source_attach(source, context_);
+  return source;
+}
+
+}  // namespace base
diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h
new file mode 100644
index 0000000..97daa8a
--- /dev/null
+++ b/base/message_pump_glib.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_PUMP_GLIB_H_
+
+#include <glib.h>
+
+#include "base/message_pump.h"
+#include "base/time.h"
+
+namespace base {
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// OS_LINUX platforms using GLib.
+class MessagePumpForUI : public MessagePump {
+ public:
+  MessagePumpForUI();
+  ~MessagePumpForUI();
+
+  virtual void Run(Delegate* delegate);
+  virtual void Quit();
+  virtual void ScheduleWork();
+  virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+
+ private:
+  // We may make recursive calls to Run, so we save state that needs to be
+  // separate between them in this structure type.
+  struct RunState {
+    // This is the delegate argument passed to Run.
+    Delegate* delegate;
+    // This tells us when to exit the event pump.
+    bool keep_running;
+    // This tells our work source when to dispatch DoWork and DoDelayedWork.
+    bool should_do_work;
+    // This tells our idle source when to dispatch DoIdleWork.
+    bool should_do_idle_work;
+    // Unlike the work source, which is shared by all calls to Run, each Run
+    // call gets its own idle source because we need to destroy it when we have
+    // no idle work, and we don't want to destroy someone else's source.
+    GSource* idle_source;
+  };
+
+  struct WorkSource : GSource {
+    MessagePumpForUI* self;
+  };
+
+  // The source with these callbacks remain in the main loop forever.  They
+  // will dispatch DoWork and DoDelayedWork, and calculate when and how long
+  // to block when GLib calls poll internally.
+  static GSourceFuncs WorkSourceFuncs;
+  static gboolean WorkSourcePrepare(GSource* source, gint* timeout_ms);
+  static gboolean WorkSourceCheck(GSource* source);
+  static gboolean WorkSourceDispatch(GSource* source, GSourceFunc unused_func,
+                                     gpointer unused_data);
+
+  // The source that uses these callbacks is added as an idle source, which
+  // means GLib will call it when there is no other work to do.  We continue
+  // doing work as long as DoIdleWork or the other work functions return true.
+  // Once no work remains, we remove the idle source so GLib will block instead
+  // of firing it.  Then we re-add it when we wake up.
+  static GSourceFuncs IdleSourceFuncs;
+  static gboolean IdleSourcePrepare(GSource* source, gint* timeout_ms);
+  static gboolean IdleSourceCheck(GSource* source);
+  static gboolean IdleSourceDispatch(GSource* source, GSourceFunc unused_func,
+                                     gpointer unused_data);
+
+  // This adds a GLib source to the main loop.
+  GSource* AddSource(GSourceFuncs* funcs, gint priority,
+                     GPollFD* optional_poll_fd);
+
+  RunState* state_;
+
+  // This is a GLib structure that we can add event sources to.  We use the
+  // default GLib context, which is the one to which all GTK events are
+  // dispatched.
+  GMainContext* context_;
+
+  // This is the time when we need to do delayed work.
+  Time delayed_work_time_;
+
+  // We use a pipe to schedule work in a thread-safe way that doesn't interfere
+  // with our state.  When ScheduleWork is called, we write into the pipe which
+  // ensures poll will not sleep, since we use the read end as an event source.
+  // When we find data pending on the pipe, we clear it out and know we have
+  // been given new work.
+  int write_fd_work_scheduled_;
+  int read_fd_work_scheduled_;
+
+  // The work source.  It is shared by all calls to Run and destroyed when
+  // the message pump is destroyed.
+  GSource* work_source_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_GLIB_H_