Use libevent, second try.  Changes this time:
- remove bogus include of base/completion_callback.h
- add DEPS rules to allow including third_party/libevent

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@2371 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/DEPS b/base/DEPS
index c6e9550..40bf9978 100644
--- a/base/DEPS
+++ b/base/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+third_party/zlib",
+  "+third_party/libevent",
 ]
diff --git a/base/SConscript b/base/SConscript
index bf4a3fd6..496ba0a 100644
--- a/base/SConscript
+++ b/base/SConscript
@@ -159,6 +159,7 @@
       'base_paths_linux.cc',
       'file_util_linux.cc',
       'hmac_nss.cc',
+      'message_pump_libevent.cc',
       'nss_init.cc',
       'sys_string_conversions_linux.cc',
       'worker_pool.cc',
@@ -190,6 +191,7 @@
     LIBS = [
         'base',
         'base_gfx',
+        'event',
         'gtest',
         'icuuc',
         'libpng',
diff --git a/base/message_loop.cc b/base/message_loop.cc
index 4b95532..48e05eb 100644
--- a/base/message_loop.cc
+++ b/base/message_loop.cc
@@ -13,6 +13,10 @@
 #include "base/string_util.h"
 #include "base/thread_local.h"
 
+#if defined(OS_POSIX)
+#include "base/message_pump_libevent.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.
 static base::LazyInstance<base::ThreadLocalPointer<MessageLoop> > lazy_tls_ptr(
@@ -78,6 +82,12 @@
   } else {
     pump_ = new base::MessagePumpWin();
   }
+#elif defined(OS_POSIX)
+  if (type_ == TYPE_IO) {
+    pump_ = new base::MessagePumpLibevent();
+  } else {
+    pump_ = new base::MessagePumpDefault();
+  }
 #else
   pump_ = new base::MessagePumpDefault();
 #endif
@@ -561,4 +571,14 @@
   pump_win()->WatchObject(object, watcher);
 }
 
-#endif  // defined(OS_WIN)
+#elif defined(OS_POSIX)
+
+void MessageLoopForIO::WatchSocket(int socket, short interest_mask, 
+                                   struct event* e, Watcher* watcher) {
+  pump_libevent()->WatchSocket(socket, interest_mask, e, watcher);
+}
+
+void MessageLoopForIO::UnwatchSocket(struct event* e) {
+  pump_libevent()->UnwatchSocket(e);
+}
+#endif
diff --git a/base/message_loop.h b/base/message_loop.h
index a65a2e8..51093c6 100644
--- a/base/message_loop.h
+++ b/base/message_loop.h
@@ -21,6 +21,8 @@
 // We need this to declare base::MessagePumpWin::Dispatcher, which we should
 // really just eliminate.
 #include "base/message_pump_win.h"
+#elif defined(OS_POSIX)
+#include "base/message_pump_libevent.h"
 #endif
 
 // A MessageLoop is used to process events for a particular thread.  There is
@@ -274,6 +276,11 @@
   base::MessagePumpWin* pump_win() {
     return static_cast<base::MessagePumpWin*>(pump_.get());
   }
+#elif defined(OS_POSIX)
+  base::MessagePumpLibevent* pump_libevent() {
+    return static_cast<base::MessagePumpLibevent*>(pump_.get());
+  }
+ protected:
 #endif
 
   // A function to encapsulate all the exception handling capability in the
@@ -450,6 +457,14 @@
 
   // Please see MessagePumpWin for definitions of these methods.
   void WatchObject(HANDLE object, Watcher* watcher);
+
+#elif defined(OS_POSIX)
+  typedef base::MessagePumpLibevent::Watcher Watcher;
+
+  // Please see MessagePumpLibevent for definitions of these methods.
+  void WatchSocket(int socket, short interest_mask, 
+                   struct event* e, Watcher* watcher);
+  void UnwatchSocket(struct event* e);
 #endif  // defined(OS_WIN)
 };
 
diff --git a/base/message_pump_libevent.cc b/base/message_pump_libevent.cc
new file mode 100644
index 0000000..38e7db6
--- /dev/null
+++ b/base/message_pump_libevent.cc
@@ -0,0 +1,179 @@
+// 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_libevent.h"
+
+#include "base/logging.h"
+#include "base/time.h"
+#include "third_party/libevent/event.h"
+
+#include <fcntl.h>
+
+namespace base {
+
+// Return 0 on success
+// Too small a function to bother putting in a library?
+static int SetNonBlocking(int fd)
+{
+    int flags = fcntl(fd, F_GETFL, 0);
+    if (-1 == flags)
+      flags = 0;
+    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+// Called if a byte is received on the wakeup pipe.
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+
+  base::MessagePumpLibevent* that = 
+              static_cast<base::MessagePumpLibevent*>(context);
+  DCHECK(that->wakeup_pipe_out_ == socket);
+
+  // Remove and discard the wakeup byte.
+  char buf;
+  int nread = read(socket, &buf, 1);
+  DCHECK(nread == 1);
+  // Tell libevent to break out of inner loop.
+  event_base_loopbreak(that->event_base_);
+}
+
+MessagePumpLibevent::MessagePumpLibevent()
+    : keep_running_(true),
+      in_run_(false),
+      event_base_(event_base_new()),
+      wakeup_pipe_in_(-1),
+      wakeup_pipe_out_(-1) {
+  if (!Init())
+     NOTREACHED();
+}
+
+bool MessagePumpLibevent::Init() {
+  int fds[2];
+  if (pipe(fds))
+    return false;
+  if (SetNonBlocking(fds[0]))
+    return false;
+  if (SetNonBlocking(fds[1]))
+    return false;
+  wakeup_pipe_out_ = fds[0];
+  wakeup_pipe_in_ = fds[1];
+
+  wakeup_event_ = new event;
+  event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST, 
+	    OnWakeup, this);
+  event_base_set(event_base_, wakeup_event_);
+
+  if (event_add(wakeup_event_, 0))
+    return false;
+  return true;
+}
+
+MessagePumpLibevent::~MessagePumpLibevent() {
+  DCHECK(wakeup_event_);
+  DCHECK(event_base_);
+  event_del(wakeup_event_);
+  delete wakeup_event_;
+  event_base_free(event_base_);
+}
+
+void MessagePumpLibevent::WatchSocket(int socket, short interest_mask, 
+                                      event* e, Watcher* watcher) {
+
+  // Set current interest mask and message pump for this event
+  event_set(e, socket, interest_mask, OnReadinessNotification, watcher);
+
+  // Tell libevent which message pump this socket will belong to when we add it.
+  event_base_set(event_base_, e);
+
+  // Add this socket to the list of monitored sockets.
+  if (event_add(e, NULL))
+    NOTREACHED();
+}
+
+void MessagePumpLibevent::UnwatchSocket(event* e) {
+  // Remove this socket from the list of monitored sockets.
+  if (event_del(e))
+    NOTREACHED();
+}
+
+void MessagePumpLibevent::OnReadinessNotification(int socket, short flags, 
+                                                  void* context) {
+  // The given socket is ready for I/O.
+  // Tell the owner what kind of I/O the socket is ready for.
+  Watcher* watcher = static_cast<Watcher*>(context);
+  watcher->OnSocketReady(flags);
+}
+
+// Reentrant!
+void MessagePumpLibevent::Run(Delegate* delegate) {
+  DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+
+  bool old_in_run = in_run_;
+  in_run_ = true;
+
+  for (;;) {
+    bool did_work = delegate->DoWork();
+    if (!keep_running_)
+      break;
+
+    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    did_work = delegate->DoIdleWork();
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    // EVLOOP_ONCE tells libevent to only block once,
+    // but to service all pending events when it wakes up.
+    if (delayed_work_time_.is_null()) {
+      event_base_loop(event_base_, EVLOOP_ONCE);
+    } else {
+      TimeDelta delay = delayed_work_time_ - Time::Now();
+      if (delay > TimeDelta()) {
+        struct timeval poll_tv;
+        poll_tv.tv_sec = delay.InSeconds();
+        poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
+        event_base_loopexit(event_base_, &poll_tv);
+        event_base_loop(event_base_, EVLOOP_ONCE);
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = Time();
+      }
+    }
+  }
+
+  keep_running_ = true;
+  in_run_ = old_in_run;
+}
+
+void MessagePumpLibevent::Quit() {
+  DCHECK(in_run_);
+  // Tell both libevent and Run that they should break out of their loops.
+  keep_running_ = false;
+  ScheduleWork();
+}
+
+void MessagePumpLibevent::ScheduleWork() {
+  // Tell libevent (in a threadsafe way) that it should break out of its loop.
+  char buf = 0;
+  int nwrite = write(wakeup_pipe_in_, &buf, 1);
+  DCHECK(nwrite == 1);
+}
+
+void MessagePumpLibevent::ScheduleDelayedWork(const Time& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+}  // namespace base
+
diff --git a/base/message_pump_libevent.h b/base/message_pump_libevent.h
new file mode 100644
index 0000000..7534e50
--- /dev/null
+++ b/base/message_pump_libevent.h
@@ -0,0 +1,89 @@
+// Copyright (c) 2006-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_LIBEVENT_H_
+#define BASE_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class MessagePumpLibevent : public MessagePump {
+ public:
+  // Used with WatchObject to asynchronously monitor the I/O readiness of a
+  // socket.
+  class Watcher {
+   public:
+    virtual ~Watcher() {}
+    // Called from MessageLoop::Run when a ready socket is detected.
+    virtual void OnSocketReady(short eventmask) = 0;
+  };
+
+  MessagePumpLibevent();
+  virtual ~MessagePumpLibevent();
+
+  // Have the current thread's message loop watch for a ready socket.
+  // Caller must provide a struct event for this socket for libevent's use.
+  // The event and interest_mask fields are defined in libevent.
+  // Returns true on success.  
+  // TODO(dkegel): hide libevent better; abstraction still too leaky
+  // TODO(dkegel): better error handing
+  // TODO(dkegel): switch to edge-triggered readiness notification
+  void WatchSocket(int socket, short interest_mask, event* e, Watcher*);
+
+  // Stop watching a socket.
+  // Event was previously initialized by WatchSocket.
+  void UnwatchSocket(event* e);
+
+  // MessagePump methods:
+  virtual void Run(Delegate* delegate);
+  virtual void Quit();
+  virtual void ScheduleWork();
+  virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+
+ private:
+
+  // Risky part of constructor.  Returns true on success.
+  bool Init();
+
+  // This flag is set to false when Run should return.
+  bool keep_running_;
+
+  // This flag is set when inside Run.
+  bool in_run_;
+
+  // The time at which we should call DoDelayedWork.
+  Time delayed_work_time_;
+
+  // Libevent dispatcher.  Watches all sockets registered with it, and sends 
+  // readiness callbacks when a socket is ready for I/O.
+  event_base* event_base_;
+
+  // Called by libevent to tell us a registered socket is ready
+  static void OnReadinessNotification(int socket, short flags, void* context);
+
+  // Unix pipe used to implement ScheduleWork()
+  // ... callback; called by libevent inside Run() when pipe is ready to read
+  static void OnWakeup(int socket, short flags, void* context);
+  // ... write end; ScheduleWork() writes a single byte to it 
+  int wakeup_pipe_in_;
+  // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+  int wakeup_pipe_out_;
+  // ... libevent wrapper for read end
+  event* wakeup_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_LIBEVENT_H_
+