Lift 1024 open files limit (switch to curl polling API) (#893)

* Switch to new libcurl's polling interface

* Drop unused includes

* Use NOFILE limit value defined by operating system

* Avoid tight loops, ensure blocking for a small timeout

When there are no file descriptors to wait for, select() would work the
same as sleep(). But curl_multi_wait() returns immediately in this case,
so we need to add explicit wait to avoid tight loops.

Documentation: https://curl.haxx.se/libcurl/c/curl_multi_timeout.html
Discussion: https://curl.haxx.se/mail/lib-2018-03/0074.html

* Bump libcurl minimum version to 7.28.0
This commit is contained in:
Vitaly Potyarkin 2020-07-29 05:38:27 +03:00 committed by GitHub
parent 9da4abb003
commit 2da97b25fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 20 additions and 83 deletions

View File

@ -97,7 +97,7 @@ string(SUBSTRING "${TR_VCS_REVISION}" 0 10 TR_VCS_REVISION)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CURL_MINIMUM 7.15.4)
set(CURL_MINIMUM 7.28.0)
set(EVENT2_MINIMUM 2.0.10)
set(OPENSSL_MINIMUM 0.9.7)
set(CYASSL_MINIMUM 3.0)

View File

@ -39,7 +39,7 @@ AM_CONDITIONAL(HAVE_REVISION_FILE, test -f REVISION)
##
##
CURL_MINIMUM=7.15.4
CURL_MINIMUM=7.28.0
AC_SUBST(CURL_MINIMUM)
LIBEVENT_MINIMUM=2.0.10
AC_SUBST(LIBEVENT_MINIMUM)

View File

@ -10,11 +10,6 @@
#include <inttypes.h>
#include <string.h>
#ifndef _WIN32
#include <sys/time.h> /* getrlimit */
#include <sys/resource.h> /* getrlimit */
#endif
#include "transmission.h"
#include "error.h"
#include "error-types.h"
@ -389,27 +384,6 @@ static void ensureSessionFdInfoExists(tr_session* session)
i = tr_new0(struct tr_fdInfo, 1);
fileset_construct(&i->fileset, FILE_CACHE_SIZE);
session->fdInfo = i;
#ifndef _WIN32
/* set the open-file limit to the largest safe size wrt FD_SETSIZE */
struct rlimit limit;
if (getrlimit(RLIMIT_NOFILE, &limit) == 0)
{
int const old_limit = (int)limit.rlim_cur;
int const new_limit = MIN(limit.rlim_max, FD_SETSIZE);
if (new_limit != old_limit)
{
limit.rlim_cur = new_limit;
setrlimit(RLIMIT_NOFILE, &limit);
getrlimit(RLIMIT_NOFILE, &limit);
tr_logAddInfo("Changed open file limit from %d to %d", old_limit, (int)limit.rlim_cur);
}
}
#endif
}
}

View File

@ -11,9 +11,6 @@
#ifdef _WIN32
#include <windows.h>
#include <wincrypt.h>
#include <ws2tcpip.h>
#else
#include <sys/select.h>
#endif
#include <curl/curl.h>
@ -391,41 +388,6 @@ struct tr_web_task* tr_webRunWebseed(tr_torrent* tor, char const* url, char cons
return tr_webRunImpl(tor->session, tr_torrentId(tor), url, range, NULL, done_func, done_func_user_data, buffer);
}
/**
* Portability wrapper for select().
*
* http://msdn.microsoft.com/en-us/library/ms740141%28VS.85%29.aspx
* On win32, any two of the parameters, readfds, writefds, or exceptfds,
* can be given as null. At least one must be non-null, and any non-null
* descriptor set must contain at least one handle to a socket.
*/
static void tr_select(int nfds, fd_set* r_fd_set, fd_set* w_fd_set, fd_set* c_fd_set, struct timeval* t)
{
#ifdef _WIN32
(void)nfds;
if (r_fd_set->fd_count == 0 && w_fd_set->fd_count == 0 && c_fd_set->fd_count == 0)
{
long int const msec = t->tv_sec * 1000 + t->tv_usec / 1000;
tr_wait_msec(msec);
}
else if (select(0, r_fd_set->fd_count != 0 ? r_fd_set : NULL, w_fd_set->fd_count != 0 ? w_fd_set : NULL,
c_fd_set->fd_count != 0 ? c_fd_set : NULL, t) == -1)
{
char errstr[512];
int const e = EVUTIL_SOCKET_ERROR();
tr_net_strerror(errstr, sizeof(errstr), e);
dbgmsg("Error: select (%d) %s", e, errstr);
}
#else
select(nfds, r_fd_set, w_fd_set, c_fd_set, t);
#endif
}
static void tr_webThreadFunc(void* vsession)
{
char* str;
@ -434,6 +396,7 @@ static void tr_webThreadFunc(void* vsession)
int taskCount = 0;
struct tr_web_task* task;
tr_session* session = vsession;
uint32_t repeats = 0;
/* try to enable ssl for https support; but if that fails,
* try a plain vanilla init */
@ -473,6 +436,7 @@ static void tr_webThreadFunc(void* vsession)
for (;;)
{
long msec;
int numfds;
int unused;
CURLMsg* msg;
CURLMcode mcode;
@ -538,28 +502,27 @@ static void tr_webThreadFunc(void* vsession)
if (msec > 0)
{
int usec;
int max_fd;
struct timeval t;
fd_set r_fd_set;
fd_set w_fd_set;
fd_set c_fd_set;
max_fd = 0;
FD_ZERO(&r_fd_set);
FD_ZERO(&w_fd_set);
FD_ZERO(&c_fd_set);
curl_multi_fdset(multi, &r_fd_set, &w_fd_set, &c_fd_set, &max_fd);
if (msec > THREADFUNC_MAX_SLEEP_MSEC)
{
msec = THREADFUNC_MAX_SLEEP_MSEC;
}
usec = msec * 1000;
t.tv_sec = usec / 1000000;
t.tv_usec = usec % 1000000;
tr_select(max_fd + 1, &r_fd_set, &w_fd_set, &c_fd_set, &t);
curl_multi_wait(multi, NULL, 0, msec, &numfds);
if (!numfds)
{
repeats++;
if (repeats > 1)
{
/* curl_multi_wait() returns immediately if there are
* no fds to wait for, so we need an explicit wait here
* to emulate select() behavior */
tr_wait_msec(MIN(msec, THREADFUNC_MAX_SLEEP_MSEC / 2));
}
}
else
{
repeats = 0;
}
}
/* call curl_multi_perform() */