Преглед изворни кода

Try to set sane limits for RLIMIT_NO_FILE

E.g. on OSX the default is 256, which isn't exactly compatible with
torrent downloads.

Closes GH-257
Nils Maier пре 11 година
родитељ
комит
8732a24433
7 измењених фајлова са 85 додато и 0 уклоњено
  1. 1 0
      configure.ac
  2. 14 0
      doc/manual-src/en/aria2c.rst
  3. 38 0
      src/Context.cc
  4. 19 0
      src/OptionHandlerFactory.cc
  5. 2 0
      src/prefs.cc
  6. 2 0
      src/prefs.h
  7. 9 0
      src/usage_text.h

+ 1 - 0
configure.ac

@@ -646,6 +646,7 @@ AC_CHECK_HEADERS([argz.h \
                   strings.h \
                   strings.h \
                   sys/ioctl.h \
                   sys/ioctl.h \
                   sys/param.h \
                   sys/param.h \
+                  sys/resource.h \
                   sys/signal.h \
                   sys/signal.h \
                   sys/socket.h \
                   sys/socket.h \
                   sys/time.h \
                   sys/time.h \

+ 14 - 0
doc/manual-src/en/aria2c.rst

@@ -1186,6 +1186,20 @@ Advanced Options
   you take commonly used values from RFC, network vendors'
   you take commonly used values from RFC, network vendors'
   documentation, Wikipedia or any other source, use them as they are.
   documentation, Wikipedia or any other source, use them as they are.
 
 
+.. option:: --rlimit-nofile=NUM
+
+  Set the soft limit of open file descriptors.
+  This open will only have effect when:
+
+    a) The system supports it (posix)
+    b) The limit does not exceed the hard limit.
+    c) The specified limit is larger than the current soft limit.
+
+  This is equivalent to setting nofile via ulimit,
+  except that it will never decrease the limit.
+
+  This option is only available on systems supporting the rlimit API.
+
 .. option:: --enable-color[=true|false]
 .. option:: --enable-color[=true|false]
 
 
   Enable color output for a terminal.
   Enable color output for a terminal.

+ 38 - 0
src/Context.cc

@@ -37,6 +37,11 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <getopt.h>
 #include <getopt.h>
 
 
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif // HAVE_SYS_RESOURCE_H
+
+
 #include <numeric>
 #include <numeric>
 #include <vector>
 #include <vector>
 #include <iostream>
 #include <iostream>
@@ -180,6 +185,39 @@ Context::Context(bool standalone,
   A2_LOG_INFO(usedLibs());
   A2_LOG_INFO(usedLibs());
   A2_LOG_INFO(MSG_LOGGING_STARTED);
   A2_LOG_INFO(MSG_LOGGING_STARTED);
 
 
+#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_NOFILE)
+  rlimit r = { 0, 0 };
+  if (getrlimit(RLIMIT_NOFILE, &r) >= 0 && r.rlim_cur != RLIM_INFINITY) {
+    // Thanks portability, for making it easy :p
+    auto rlim_new = r.rlim_cur; // So we get the right type for free.
+    if (r.rlim_cur != RLIM_INFINITY) {
+      rlim_new = op->getAsInt(PREF_RLIMIT_NOFILE);
+      rlim_new = std::max(r.rlim_cur, rlim_new);
+      if (r.rlim_max != RLIM_INFINITY) {
+        rlim_new = std::min(r.rlim_max, rlim_new);
+      }
+    }
+    if (rlim_new != r.rlim_cur) {
+      if (setrlimit(RLIMIT_NOFILE, &r) != 0) {
+        int errNum = errno;
+        A2_LOG_WARN(fmt("Failed to set rlimit NO_FILE from %" PRIu64 " to "
+                        "%" PRIu64 ": %s",
+                        (uint64_t)r.rlim_cur, (uint64_t)rlim_new,
+                        util::safeStrerror(errNum).c_str()));
+      }
+      else {
+        A2_LOG_DEBUG(fmt("Set rlimit NO_FILE from %" PRIu64 " to %" PRIu64,
+                         (uint64_t)r.rlim_cur, (uint64_t)rlim_new));
+      }
+    }
+    else {
+      rlim_new = op->getAsInt(PREF_RLIMIT_NOFILE);
+      A2_LOG_DEBUG(fmt("Not setting rlimit NO_FILE: %" PRIu64 " >= %" PRIu64,
+                       (uint64_t)r.rlim_cur, (uint64_t)rlim_new));
+    }
+  }
+#endif // defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_NOFILE)
+
   if(op->getAsBool(PREF_DISABLE_IPV6)) {
   if(op->getAsBool(PREF_DISABLE_IPV6)) {
     SocketCore::setProtocolFamily(AF_INET);
     SocketCore::setProtocolFamily(AF_INET);
     // Get rid of AI_ADDRCONFIG. It causes name resolution error
     // Get rid of AI_ADDRCONFIG. It causes name resolution error

+ 19 - 0
src/OptionHandlerFactory.cc

@@ -755,6 +755,25 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
     op->addTag(TAG_ADVANCED);
     op->addTag(TAG_ADVANCED);
     handlers.push_back(op);
     handlers.push_back(op);
   }
   }
+#ifdef HAVE_SYS_RESOURCE_H
+  {
+    OptionHandler* op(new NumberOptionHandler
+                      (PREF_RLIMIT_NOFILE,
+                       TEXT_RLIMIT_NOFILE,
+                       // Somewhat sane default that most *nix use.
+                       // Some other *nix, like OSX, have insane defaults like
+                       // 256, hence better *not* get the default value from
+                       // getrlimit().
+                       "1024",
+                       // 1 should not be a problem in practise, since the code
+                       // will only adjust if the specified value > the current
+                       // soft limit.
+                       // And sane systems have a default soft limit > 1.
+                       1));
+    op->addTag(TAG_ADVANCED);
+    handlers.push_back(op);
+  }
+#endif // HAVE_SYS_RESOURCE_H
   {
   {
     OptionHandler* op(new BooleanOptionHandler
     OptionHandler* op(new BooleanOptionHandler
                       (PREF_SELECT_LEAST_USED_HOST,
                       (PREF_SELECT_LEAST_USED_HOST,

+ 2 - 0
src/prefs.cc

@@ -365,6 +365,8 @@ PrefPtr PREF_RPC_SECRET = makePref("rpc-secret");
 PrefPtr PREF_DSCP = makePref("dscp");
 PrefPtr PREF_DSCP = makePref("dscp");
 // values: true | false
 // values: true | false
 PrefPtr PREF_PAUSE_METADATA = makePref("pause-metadata");
 PrefPtr PREF_PAUSE_METADATA = makePref("pause-metadata");
+// values: 1*digit
+PrefPtr PREF_RLIMIT_NOFILE = makePref("rlimit-nofile");
 
 
 /**
 /**
  * FTP related preferences
  * FTP related preferences

+ 2 - 0
src/prefs.h

@@ -302,6 +302,8 @@ extern PrefPtr PREF_RPC_SECRET;
 extern PrefPtr PREF_DSCP;
 extern PrefPtr PREF_DSCP;
 // values: true | false
 // values: true | false
 extern PrefPtr PREF_PAUSE_METADATA;
 extern PrefPtr PREF_PAUSE_METADATA;
+// values: 1*digit
+extern PrefPtr PREF_RLIMIT_NOFILE;
 
 
 /**
 /**
  * FTP related preferences
  * FTP related preferences

+ 9 - 0
src/usage_text.h

@@ -980,6 +980,15 @@
     "                              commonly used values from RFC, network vendors'\n" \
     "                              commonly used values from RFC, network vendors'\n" \
     "                              documentation, Wikipedia or any other source,\n" \
     "                              documentation, Wikipedia or any other source,\n" \
     "                              use them as they are.")
     "                              use them as they are.")
+#define TEXT_RLIMIT_NOFILE                                              \
+  _("  --rlimit-nofile=NUM         Set the soft limit of open file descriptors.\n" \
+    "                              This open will only have effect when:\n" \
+    "                                a) The system supports it (posix)\n" \
+    "                                b) The limit does not exceed the hard limit.\n" \
+    "                                c) The specified limit is larger than the\n" \
+    "                                   current soft limit.\n" \
+    "                              This is equivalent to setting nofile via ulimit,\n" \
+    "                              except that it will never decrease the limit.")
 #define TEXT_PAUSE_METADATA                  \
 #define TEXT_PAUSE_METADATA                  \
   _(" --pause-metadata[=true|false]\n"       \
   _(" --pause-metadata[=true|false]\n"       \
     "                              Pause downloads created as a result of metadata\n" \
     "                              Pause downloads created as a result of metadata\n" \