Просмотр исходного кода

Merge branch 'libuv-eventpoll' of https://github.com/nmaier/aria2 into nmaier-libuv-eventpoll

Tatsuhiro Tsujikawa 12 лет назад
Родитель
Сommit
db2e22132d
9 измененных файлов с 619 добавлено и 22 удалено
  1. 88 16
      configure.ac
  2. 14 0
      src/DownloadEngineFactory.cc
  3. 327 0
      src/LibuvEventPoll.cc
  4. 171 0
      src/LibuvEventPoll.h
  5. 4 0
      src/Makefile.am
  6. 12 5
      src/OptionHandlerFactory.cc
  7. 1 1
      src/SocketCore.cc
  8. 1 0
      src/prefs.cc
  9. 1 0
      src/prefs.h

+ 88 - 16
configure.ac

@@ -17,13 +17,14 @@ AC_CONFIG_HEADERS([config.h])
 case "$host" in
   *mingw*)
     win_build=yes
-    LIBS="$LIBS -lws2_32 -lwsock32 -lgdi32 -lwinmm -liphlpapi"
+    LIBS="$LIBS -lws2_32 -lwsock32 -lgdi32 -lwinmm -liphlpapi -lpsapi"
     ;;
 esac
 
 AC_DEFINE_UNQUOTED([TARGET], ["$target"], [Define target-type])
 
 # Checks for arguments.
+ARIA2_ARG_WITHOUT([libuv])
 ARIA2_ARG_WITHOUT([appletls])
 ARIA2_ARG_WITHOUT([gnutls])
 ARIA2_ARG_WITHOUT([libnettle])
@@ -112,6 +113,69 @@ if test "x$with_libz" = "xyes"; then
   fi
 fi
 
+if test "x$with_libuv" = "xyes"; then
+  case "$host" in
+    *mingw*|*msvc*)
+      old_CPPFLAGS=$CPPFLAGS
+      CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600"
+      AC_SEARCH_LIBS([uv_poll_init_socket], [uv], [
+                      AC_CHECK_HEADER([uv.h], [have_libuv=yes], [have_libuv=no])
+                      break;
+                      ], [have_libuv=no])
+      if test "x$have_libuv" != "xyes"; then
+        CPPFLAGS=$old_CPPFLAGS
+      fi
+    ;;
+
+    *darwin*)
+      old_LDFLAGS=$LDFLAGS
+      LDFLAGS="$LDFLAGS -framework Foundation -framework CoreServices -framework ApplicationServices"
+      old_LIBS=$LIBS
+      LIBS="$LIBS -lm"
+      AC_SEARCH_LIBS([uv_poll_init_socket], [uv], [
+                      AC_CHECK_HEADER([uv.h], [have_libuv=yes], [have_libuv=no])
+                      break;
+                      ], [have_libuv=no])
+      if test "x$have_libuv" != "xyes"; then
+        LDFLAGS=$old_LDFLAGS
+        LIBS=$old_LIBS
+      fi
+      ;;
+
+    *)
+      dnl Yeah, sucks that luv does not bring a pkg-config or config-tool
+      AC_MSG_CHECKING([for libuv])
+      for combo in "" "-lrt" "-ldl -lrt" "-ldl -lrt -lpthread" "-lkvm"; do
+        old_LIBS=$LIBS
+        LIBS="-luv $combo $LIBS -lm"
+        AC_LINK_IFELSE([AC_LANG_SOURCE([
+extern "C" int uv_poll_init_socket(void);
+int main() { return uv_poll_init_socket(); }
+                       ])], [
+                        AC_MSG_RESULT(-luv $combo -lm)
+                        AC_CHECK_HEADER([uv.h], [have_libuv=yes], [have_libuv=no])
+                        break;
+                        ], [have_libuv=no])
+        if test "x$have_libuv" = "xyes"; then
+          break;
+        else
+          LIBS=$old_LIBS
+        fi
+      done
+      if test "x$have_libuv" != "xyes"; then
+        AC_MSG_RESULT("no")
+      fi
+    ;;
+  esac
+
+  if test "x$have_libuv" = "xyes"; then
+    AC_DEFINE([HAVE_LIBUV], [1], [Define to 1 if you have libuv.])
+  elif test "x$with_libuv_requested" = "xyes"; then
+    ARIA2_DEP_NOT_MET([libuv])
+  fi
+fi
+AM_CONDITIONAL([HAVE_LIBUV], [test "x$have_libuv" = "xyes"])
+
 if test "x$with_libxml2" = "xyes"; then
   AM_PATH_XML2([2.6.24], [have_libxml2=yes])
   if test "x$have_libxml2" = "xyes"; then
@@ -388,18 +452,25 @@ AC_HEADER_STDC
 
 case "$host" in
 	*mingw*)
-                AC_CHECK_HEADERS([windows.h \
-				  winsock2.h \
-                                  ws2tcpip.h \
-				  mmsystem.h \
-                                  io.h \
-                                  iphlpapi.h\
-                                  winioctl.h \
-                                  share.h], [], [],
-[[#ifdef HAVE_WINDOWS_H
+    AC_CHECK_HEADERS([windows.h \
+                      winsock2.h \
+                      ws2tcpip.h \
+                      mmsystem.h \
+                      io.h \
+                      iphlpapi.h\
+                      winioctl.h \
+                      share.h], [], [],
+                      [[
+#ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+#endif
+#ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+#endif
+#ifdef HAVE_WINDOWS_H
 # include <windows.h>
 #endif
-]])
+                      ]])
 		;;
 esac
 
@@ -416,8 +487,8 @@ AC_CHECK_HEADERS([argz.h \
                   netdb.h \
                   netinet/in.h \
                   netinet/tcp.h \
-		  poll.h \
-		  port.h \
+                  poll.h \
+                  port.h \
                   signal.h \
                   stddef.h \
                   stdint.h \
@@ -434,10 +505,10 @@ AC_CHECK_HEADERS([argz.h \
                   sys/uio.h \
                   termios.h \
                   unistd.h \
-		  utime.h \
+                  utime.h \
                   wchar.h \
-		  ifaddrs.h \
-		  pwd.h])
+                  ifaddrs.h \
+                  pwd.h])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_HEADER_STDBOOL
@@ -722,6 +793,7 @@ echo "CPPFLAGS:       $CPPFLAGS"
 echo "LDFLAGS:        $LDFLAGS"
 echo "LIBS:           $LIBS"
 echo "DEFS:           $DEFS"
+echo "LibUV:          $have_libuv"
 echo "SQLite3:        $have_sqlite3"
 echo "SSL Support:    $have_ssl"
 echo "AppleTLS:       $have_appletls"

+ 14 - 0
src/DownloadEngineFactory.cc

@@ -59,6 +59,9 @@
 #include "a2io.h"
 #include "DownloadContext.h"
 #include "array_fun.h"
+#ifdef HAVE_LIBUV
+# include "LibuvEventPoll.h"
+#endif // HAVE_LIBUV
 #ifdef HAVE_EPOLL
 # include "EpollEventPoll.h"
 #endif // HAVE_EPOLL
@@ -89,6 +92,17 @@ DownloadEngineFactory::newDownloadEngine
     op->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS);
   SharedHandle<EventPoll> eventPoll;
   const std::string& pollMethod = op->get(PREF_EVENT_POLL);
+#ifdef HAVE_LIBUV
+  if (pollMethod == V_LIBUV) {
+    SharedHandle<LibuvEventPoll> ep(new LibuvEventPoll());
+    if (!ep->good()) {
+      throw DL_ABORT_EX("Initializing LibuvEventPoll failed."
+                        " Try --event-poll=select");
+    }
+    eventPoll = ep;
+  }
+  else
+#endif // HAVE_LIBUV
 #ifdef HAVE_EPOLL
   if(pollMethod == V_EPOLL) {
     SharedHandle<EpollEventPoll> ep(new EpollEventPoll());

+ 327 - 0
src/LibuvEventPoll.cc

@@ -0,0 +1,327 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2010 Tatsuhiro Tsujikawa
+ * Copyright (C) 2013 Tatsuhiro Tsujikawa, Nils Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+
+#ifdef __MINGW32__
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif // _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif // __MINGW32__
+
+#include "LibuvEventPoll.h"
+
+#include <algorithm>
+#include <cstring>
+#include <numeric>
+#include <stdexcept>
+
+#include <uv.h>
+
+#include "Command.h"
+#include "LogFactory.h"
+#include "Logger.h"
+#include "a2functional.h"
+#include "fmt.h"
+#include "util.h"
+
+namespace {
+  using namespace aria2;
+
+  template<typename T>
+  static void close_callback(uv_handle_t* handle)
+  {
+    delete reinterpret_cast<T*>(handle);
+  }
+
+  static void timer_callback(uv_timer_t* handle, int status)
+  {
+    uv_stop(handle->loop);
+  }
+}
+
+namespace aria2 {
+
+LibuvEventPoll::KSocketEntry::KSocketEntry(sock_t s)
+  : SocketEntry<KCommandEvent, KADNSEvent>(s)
+{}
+
+inline int accumulateEvent(int events, const LibuvEventPoll::KEvent& event)
+{
+  return events | event.getEvents();
+}
+
+int LibuvEventPoll::KSocketEntry::getEvents() const
+{
+  int events = 0;
+#ifdef ENABLE_ASYNC_DNS
+  events = std::accumulate(adnsEvents_.begin(), adnsEvents_.end(),
+                           std::accumulate(commandEvents_.begin(),
+                                           commandEvents_.end(), 0,
+                                           accumulateEvent),
+                           accumulateEvent);
+#else // !ENABLE_ASYNC_DNS
+  events = std::accumulate(commandEvents_.begin(), commandEvents_.end(), 0,
+                           accumulateEvent);
+#endif // !ENABLE_ASYNC_DNS
+
+  return events;
+}
+
+LibuvEventPoll::LibuvEventPoll()
+{
+  loop_ = uv_loop_new();
+}
+
+LibuvEventPoll::~LibuvEventPoll()
+{
+  for (KPolls::iterator i = polls_.begin(), e = polls_.end(); i != e; ++i) {
+    i->second->close();
+  }
+  // Actually kill the polls, and timers, if any.
+  uv_run(loop_, (uv_run_mode)(UV_RUN_ONCE | UV_RUN_NOWAIT));
+
+  if (loop_) {
+    uv_loop_delete(loop_);
+    loop_ = 0;
+  }
+
+  // Need this to free only after the loop is gone.
+  polls_.clear();
+}
+
+void LibuvEventPoll::poll(const struct timeval& tv)
+{
+  const int timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+  // timeout == 0 will tick once
+  if (timeout >= 0) {
+    uv_timer_t* timer = new uv_timer_t;
+    uv_timer_init(loop_, timer);
+    uv_timer_start(timer, timer_callback, timeout, timeout);
+
+    uv_run(loop_, UV_RUN_DEFAULT);
+
+    // Remove timer again.
+    uv_timer_stop(timer);
+    uv_close((uv_handle_t*)timer, close_callback<uv_timer_t>);
+  }
+  else {
+    while (uv_run(loop_, (uv_run_mode)(UV_RUN_ONCE | UV_RUN_NOWAIT)) > 0) {}
+  }
+
+#ifdef ENABLE_ASYNC_DNS
+  // It turns out that we have to call ares_process_fd before ares's
+  // own timeout and ares may create new sockets or closes socket in
+  // their API. So we call ares_process_fd for all ares_channel and
+  // re-register their sockets.
+  for(KAsyncNameResolverEntrySet::iterator i = nameResolverEntries_.begin(),
+        eoi = nameResolverEntries_.end(); i != eoi; ++i) {
+    (*i)->processTimeout();
+    (*i)->removeSocketEvents(this);
+    (*i)->addSocketEvents(this);
+  }
+#endif // ENABLE_ASYNC_DNS
+
+  // TODO timeout of name resolver is determined in Command(AbstractCommand,
+  // DHTEntryPoint...Command)
+}
+
+int LibuvEventPoll::translateEvents(EventPoll::EventType events)
+{
+  int newEvents = 0;
+  if (EventPoll::EVENT_READ & events) {
+    newEvents |= IEV_READ;
+  }
+  if (EventPoll::EVENT_WRITE & events) {
+    newEvents |= IEV_WRITE;
+  }
+  if (EventPoll::EVENT_ERROR & events) {
+    newEvents |= IEV_ERROR;
+  }
+  if (EventPoll::EVENT_HUP & events) {
+    newEvents |= IEV_HUP;
+  }
+  return newEvents;
+}
+
+void LibuvEventPoll::pollCallback(KPoll* poll, int status, int events)
+{
+  if (status == -1) {
+    uv_err_t err = uv_last_error(loop_);
+    switch (err.code) {
+      case UV_EAGAIN:
+      case UV_EINTR:
+        return;
+      case UV_EOF:
+      case UV_ECONNABORTED:
+      case UV_ECONNREFUSED:
+      case UV_ECONNRESET:
+      case UV_ENOTCONN:
+      case UV_EPIPE:
+      case UV_ESHUTDOWN:
+        events = IEV_HUP;
+        poll->processEvents(events);
+        poll->stop();
+        uv_stop(loop_);
+        return;
+      default:
+        events = IEV_ERROR;
+        poll->processEvents(events);
+        poll->stop();
+        uv_stop(loop_);
+        return;
+    }
+  }
+
+  // Got something
+  poll->processEvents(events);
+  uv_stop(loop_);
+}
+
+bool LibuvEventPoll::addEvents(sock_t socket,
+                               const LibuvEventPoll::KEvent& event)
+{
+  SharedHandle<KSocketEntry> socketEntry(new KSocketEntry(socket));
+  KSocketEntrySet::iterator i = socketEntries_.lower_bound(socketEntry);
+
+  if (i != socketEntries_.end() && **i == *socketEntry) {
+    event.addSelf(*i);
+    KPolls::iterator poll = polls_.find(socket);
+    if (poll == polls_.end()) {
+      throw std::logic_error("Invalid socket");
+    }
+    poll->second->start();
+    return true;
+  }
+
+  socketEntries_.insert(i, socketEntry);
+  event.addSelf(socketEntry);
+  KPoll* poll = new KPoll(this, socketEntry.get(), socket);
+  polls_[socket] = poll;
+  poll->start();
+  return true;
+}
+
+bool LibuvEventPoll::addEvents(sock_t socket, Command* command, EventPoll::EventType events)
+{
+  int pollEvents = translateEvents(events);
+  return addEvents(socket, KCommandEvent(command, pollEvents));
+}
+
+#ifdef ENABLE_ASYNC_DNS
+bool LibuvEventPoll::addEvents(sock_t socket, Command* command, int events,
+                               const SharedHandle<AsyncNameResolver>& rs)
+{
+  return addEvents(socket, KADNSEvent(rs, command, socket, events));
+}
+#endif // ENABLE_ASYNC_DNS
+
+bool LibuvEventPoll::deleteEvents(sock_t socket,
+                                  const LibuvEventPoll::KEvent& event)
+{
+  SharedHandle<KSocketEntry> socketEntry(new KSocketEntry(socket));
+  KSocketEntrySet::iterator i = socketEntries_.find(socketEntry);
+
+  if (i == socketEntries_.end()) {
+    A2_LOG_DEBUG(fmt("Socket %d is not found in SocketEntries.", socket));
+    return false;
+  }
+
+  event.removeSelf(*i);
+
+  KPolls::iterator poll = polls_.find(socket);
+  if (poll == polls_.end()) {
+    return false;
+  }
+
+  if ((*i)->eventEmpty()) {
+    poll->second->close();
+    polls_.erase(poll);
+    socketEntries_.erase(i);
+    return true;
+  }
+
+  poll->second->start();
+  return true;
+}
+
+#ifdef ENABLE_ASYNC_DNS
+bool LibuvEventPoll::deleteEvents(sock_t socket, Command* command,
+                                  const SharedHandle<AsyncNameResolver>& rs)
+{
+  return deleteEvents(socket, KADNSEvent(rs, command, socket, 0));
+}
+#endif // ENABLE_ASYNC_DNS
+
+bool LibuvEventPoll::deleteEvents(sock_t socket, Command* command,
+                                  EventPoll::EventType events)
+{
+  int pollEvents = translateEvents(events);
+  return deleteEvents(socket, KCommandEvent(command, pollEvents));
+}
+
+#ifdef ENABLE_ASYNC_DNS
+bool LibuvEventPoll::addNameResolver(const SharedHandle<AsyncNameResolver>& resolver,
+                                     Command* command)
+{
+  SharedHandle<KAsyncNameResolverEntry> entry(
+      new KAsyncNameResolverEntry(resolver, command));
+  KAsyncNameResolverEntrySet::iterator itr =
+    nameResolverEntries_.lower_bound(entry);
+  if (itr != nameResolverEntries_.end() && *(*itr) == *entry) {
+    return false;
+  }
+  nameResolverEntries_.insert(itr, entry);
+  entry->addSocketEvents(this);
+  return true;
+}
+
+bool LibuvEventPoll::deleteNameResolver(const SharedHandle<AsyncNameResolver>& resolver,
+                                        Command* command)
+{
+  SharedHandle<KAsyncNameResolverEntry> entry(
+      new KAsyncNameResolverEntry(resolver, command));
+  KAsyncNameResolverEntrySet::iterator itr = nameResolverEntries_.find(entry);
+  if (itr == nameResolverEntries_.end()) {
+    return false;
+  }
+  (*itr)->removeSocketEvents(this);
+  nameResolverEntries_.erase(itr);
+  return true;
+}
+#endif // ENABLE_ASYNC_DNS
+
+} // namespace aria2

+ 171 - 0
src/LibuvEventPoll.h

@@ -0,0 +1,171 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2013 Nils Maier
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef D_LIBUV_EVENT_POLL_H
+#define D_LIBUV_EVENT_POLL_H
+
+#include "EventPoll.h"
+
+#include <map>
+#include <set>
+
+#include <uv.h>
+
+#include "Event.h"
+#include "a2functional.h"
+
+#ifdef ENABLE_ASYNC_DNS
+#include "AsyncNameResolver.h"
+#endif // ENABLE_ASYNC_DNS
+
+namespace aria2 {
+
+class LibuvEventPoll : public EventPoll {
+private:
+  class KSocketEntry;
+
+  typedef Event<KSocketEntry> KEvent;
+  typedef CommandEvent<KSocketEntry, LibuvEventPoll> KCommandEvent;
+  typedef ADNSEvent<KSocketEntry, LibuvEventPoll> KADNSEvent;
+  typedef AsyncNameResolverEntry<LibuvEventPoll> KAsyncNameResolverEntry;
+
+  friend class AsyncNameResolverEntry<LibuvEventPoll>;
+  friend int accumulateEvent(int events, const KEvent& event);
+
+  class KSocketEntry: public SocketEntry<KCommandEvent, KADNSEvent> {
+  public:
+    KSocketEntry(sock_t socket);
+    int getEvents() const;
+  };
+
+  class KPoll {
+  private:
+    LibuvEventPoll *eventer_;
+    KSocketEntry *entry_;
+    uv_poll_t handle_;
+
+    static void poll_callback(uv_poll_t* handle, int status, int events) {
+      KPoll* poll = static_cast<KPoll*>(handle->data);
+      poll->eventer_->pollCallback(poll, status, events);
+    }
+    static void close_callback(uv_handle_t* handle) {
+      delete static_cast<KPoll*>(handle->data);
+    }
+
+  public:
+    inline KPoll(LibuvEventPoll* eventer, KSocketEntry* entry, sock_t sock)
+      : eventer_(eventer), entry_(entry)
+    {
+        uv_poll_init_socket(eventer->loop_, &handle_, sock);
+        handle_.data = this;
+    }
+    inline void start() {
+      uv_poll_start(&handle_, entry_->getEvents() & IEV_RW, poll_callback);
+    }
+    inline void stop() {
+      uv_poll_stop(&handle_);
+    }
+    inline void processEvents(int events) {
+      entry_->processEvents(events);
+    }
+    inline void close() {
+      stop();
+      uv_close((uv_handle_t*)&handle_, close_callback);
+    }
+  };
+
+  typedef std::set<SharedHandle<KSocketEntry>,
+                   DerefLess<SharedHandle<KSocketEntry> > > KSocketEntrySet;
+
+  typedef std::map<sock_t, KPoll*> KPolls;
+
+#ifdef ENABLE_ASYNC_DNS
+  typedef std::set<SharedHandle<KAsyncNameResolverEntry>,
+                   DerefLess<SharedHandle<KAsyncNameResolverEntry> > >
+  KAsyncNameResolverEntrySet;
+#endif // ENABLE_ASYNC_DNS
+
+  uv_loop_t* loop_;
+  KSocketEntrySet socketEntries_;
+  KPolls polls_;
+
+#ifdef ENABLE_ASYNC_DNS
+  KAsyncNameResolverEntrySet nameResolverEntries_;
+#endif // ENABLE_ASYNC_DNS
+
+  bool addEvents(sock_t socket, const KEvent& event);
+  bool deleteEvents(sock_t socket, const KEvent& event);
+  void pollCallback(KPoll *poll, int status, int events);
+
+#ifdef ENABLE_ASYNC_DNS
+  bool addEvents(sock_t socket, Command* command, int events,
+                 const SharedHandle<AsyncNameResolver>& rs);
+  bool deleteEvents(sock_t socket, Command* command,
+                    const SharedHandle<AsyncNameResolver>& rs);
+#endif
+
+  static int translateEvents(EventPoll::EventType events);
+
+public:
+  LibuvEventPoll();
+  virtual ~LibuvEventPoll();
+
+  bool good() const { return loop_; }
+
+  virtual void poll(const struct timeval& tv);
+
+  virtual bool addEvents(sock_t socket,
+                         Command* command, EventPoll::EventType events);
+  virtual bool deleteEvents(sock_t socket,
+                            Command* command, EventPoll::EventType events);
+
+#ifdef ENABLE_ASYNC_DNS
+  virtual bool addNameResolver(const SharedHandle<AsyncNameResolver>& resolver,
+                               Command* command);
+  virtual bool deleteNameResolver(
+      const SharedHandle<AsyncNameResolver>& resolver, Command* command);
+#endif // ENABLE_ASYNC_DNS
+
+  static const int IEV_READ = UV_READABLE;
+  static const int IEV_WRITE = UV_WRITABLE;
+  static const int IEV_RW = UV_READABLE | UV_WRITABLE;
+
+  // Make sure these do not interfere with the uv_poll API later.
+  static const int IEV_ERROR = 128;
+  static const int IEV_HUP = 255;
+};
+
+} // namespace aria2
+
+#endif // D_LIBUV_EVENT_POLL_H

+ 4 - 0
src/Makefile.am

@@ -629,6 +629,10 @@ if HAVE_KQUEUE
 SRCS += KqueueEventPoll.cc KqueueEventPoll.h
 endif # HAVE_KQUEUE
 
+if HAVE_LIBUV
+SRCS += LibuvEventPoll.cc LibuvEventPoll.h
+endif # HAVE_LIBUV
+
 AR = @AR@
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)

+ 12 - 5
src/OptionHandlerFactory.cc

@@ -338,6 +338,9 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
 #ifdef HAVE_PORT_ASSOCIATE
       V_PORT,
 #endif // HAVE_PORT_ASSOCIATE
+#ifdef HAVE_LIBUV
+      V_LIBUV,
+#endif // HAVE_LIBUV
 #ifdef HAVE_POLL
       V_POLL,
 #endif // HAVE_POLL
@@ -346,15 +349,19 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
     OptionHandler* op(new ParameterOptionHandler
                       (PREF_EVENT_POLL,
                        TEXT_EVENT_POLL,
-#ifdef HAVE_EPOLL
+#if defined(HAVE_EPOLL)
                        V_EPOLL,
-#elif HAVE_KQUEUE
+#elif defined(HAVE_KQUEUE)
                        V_KQUEUE,
-#elif HAVE_PORT_ASSOCIATE
+#elif defined(HAVE_PORT_ASSOCIATE)
                        V_PORT,
-#else
+#elif defined(HAVE_LIBUV)
+                       V_LIBUV,
+#elif defined(HAVE_POLL)
+                       V_POLL,
+#else // defined(HAVE_EPOLL)
                        V_SELECT,
-#endif // !HAVE_EPOLL
+#endif // defined(HAVE_EPOLL)
                        std::vector<std::string>
                        (vbegin(params), vend(params))));
     op->addTag(TAG_ADVANCED);

+ 1 - 1
src/SocketCore.cc

@@ -1223,7 +1223,7 @@ const uint32_t APIPA_IPV4_END = 2852061183u; // 169.254.255.255
 
 void checkAddrconfig()
 {
-#ifdef __MINGW32__
+#ifdef HAVE_IPHLPAPI_H
   A2_LOG_INFO("Checking configured addresses");
   ULONG bufsize = 15*1024;
   ULONG retval = 0;

+ 1 - 0
src/prefs.cc

@@ -153,6 +153,7 @@ const std::string V_ERROR("error");
 const std::string V_INORDER("inorder");
 const std::string V_FEEDBACK("feedback");
 const std::string V_ADAPTIVE("adaptive");
+const std::string V_LIBUV("libuv");
 const std::string V_EPOLL("epoll");
 const std::string V_KQUEUE("kqueue");
 const std::string V_PORT("port");

+ 1 - 0
src/prefs.h

@@ -88,6 +88,7 @@ extern const std::string V_ERROR;
 extern const std::string V_INORDER;
 extern const std::string V_FEEDBACK;
 extern const std::string V_ADAPTIVE;
+extern const std::string V_LIBUV;
 extern const std::string V_EPOLL;
 extern const std::string V_KQUEUE;
 extern const std::string V_PORT;