mirror of
https://github.com/curl/curl.git
synced 2026-08-24 23:43:40 +03:00
When transferring 500 downloads in parallel with a c-ares enabled build only
to find that it crashed miserably, and this was due to some select()isms left in the code. This was due to API restrictions in c-ares 1.3.x, but with the upcoming c-ares 1.4.0 this is no longer the case so now libcurl runs much better with c-ares and the multi interface with > 1024 file descriptors in use.
This commit is contained in:
parent
713c9f8602
commit
4c663ba9a8
8 changed files with 92 additions and 263 deletions
221
lib/select.c
221
lib/select.c
|
|
@ -482,227 +482,6 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
|
|||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a wrapper around select(). It uses poll() when a fine
|
||||
* poll() is available, in order to avoid limits with FD_SETSIZE,
|
||||
* otherwise select() is used. An error is returned if select() is
|
||||
* being used and a the number of file descriptors is larger than
|
||||
* FD_SETSIZE. A NULL timeout pointer makes this function wait
|
||||
* indefinitely, unles no valid file descriptor is given, when this
|
||||
* happens the NULL timeout is ignored and the function times out
|
||||
* immediately. When compiled with CURL_ACKNOWLEDGE_EINTR defined,
|
||||
* EINTR condition is honored and function might exit early without
|
||||
* awaiting timeout, otherwise EINTR will be ignored.
|
||||
*
|
||||
* Return values:
|
||||
* -1 = system call error or nfds > FD_SETSIZE
|
||||
* 0 = timeout
|
||||
* N = number of file descriptors kept in file descriptor sets.
|
||||
*/
|
||||
int Curl_select(int nfds,
|
||||
fd_set *fds_read, fd_set *fds_write, fd_set *fds_excep,
|
||||
struct timeval *timeout)
|
||||
{
|
||||
struct timeval initial_tv;
|
||||
int timeout_ms;
|
||||
int pending_ms = 0;
|
||||
int error;
|
||||
int r;
|
||||
#ifdef HAVE_POLL_FINE
|
||||
struct pollfd small_fds[SMALL_POLLNFDS];
|
||||
struct pollfd *poll_fds;
|
||||
int ix;
|
||||
int fd;
|
||||
int poll_nfds = 0;
|
||||
#else
|
||||
struct timeval pending_tv;
|
||||
struct timeval *ptimeout;
|
||||
#endif
|
||||
int ret = 0;
|
||||
|
||||
if ((nfds < 0) ||
|
||||
((nfds > 0) && (!fds_read && !fds_write && !fds_excep))) {
|
||||
SET_SOCKERRNO(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
if ((timeout->tv_sec < 0) ||
|
||||
(timeout->tv_usec < 0) ||
|
||||
(timeout->tv_usec >= 1000000)) {
|
||||
SET_SOCKERRNO(EINVAL);
|
||||
return -1;
|
||||
}
|
||||
timeout_ms = (int)(timeout->tv_sec * 1000) +
|
||||
(int)(timeout->tv_usec / 1000);
|
||||
}
|
||||
else {
|
||||
timeout_ms = -1;
|
||||
}
|
||||
|
||||
if ((!nfds) || (!fds_read && !fds_write && !fds_excep)) {
|
||||
r = wait_ms(timeout_ms);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Avoid initial timestamp, avoid gettimeofday() call, when elapsed
|
||||
time in this function does not need to be measured. This happens
|
||||
when function is called with a zero timeout in the timeval struct
|
||||
referenced argument or when a NULL pointer is received as timeval
|
||||
reference indicating a blocking call should be performed. */
|
||||
|
||||
if (timeout_ms > 0) {
|
||||
pending_ms = timeout_ms;
|
||||
initial_tv = curlx_tvnow();
|
||||
}
|
||||
|
||||
#ifdef HAVE_POLL_FINE
|
||||
|
||||
if (fds_read || fds_write || fds_excep) {
|
||||
fd = nfds;
|
||||
while (fd--) {
|
||||
if ((fds_read && (0 != FD_ISSET(fd, fds_read))) ||
|
||||
(fds_write && (0 != FD_ISSET(fd, fds_write))) ||
|
||||
(fds_excep && (0 != FD_ISSET(fd, fds_excep))))
|
||||
poll_nfds++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!poll_nfds)
|
||||
poll_fds = NULL;
|
||||
else if (poll_nfds <= SMALL_POLLNFDS)
|
||||
poll_fds = small_fds;
|
||||
else {
|
||||
poll_fds = malloc(poll_nfds * sizeof(struct pollfd));
|
||||
if (!poll_fds) {
|
||||
SET_SOCKERRNO(ENOBUFS);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (poll_fds) {
|
||||
int events;
|
||||
ix = 0;
|
||||
fd = nfds;
|
||||
while (fd--) {
|
||||
events = 0;
|
||||
if (fds_read && (0 != FD_ISSET(fd, fds_read)))
|
||||
events |= (POLLRDNORM|POLLIN);
|
||||
if (fds_write && (0 != FD_ISSET(fd, fds_write)))
|
||||
events |= (POLLWRNORM|POLLOUT);
|
||||
if (fds_excep && (0 != FD_ISSET(fd, fds_excep)))
|
||||
events |= (POLLRDBAND|POLLPRI);
|
||||
if (events) {
|
||||
poll_fds[ix].events = events;
|
||||
poll_fds[ix].fd = fd;
|
||||
poll_fds[ix].revents = 0;
|
||||
ix++;
|
||||
if(ix == poll_nfds)
|
||||
/* since we know this is the total amount of descriptors with
|
||||
interesting actions, we can skip the rest of the loop at this
|
||||
point */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if (timeout_ms < 0)
|
||||
pending_ms = -1;
|
||||
else if (!timeout_ms)
|
||||
pending_ms = 0;
|
||||
r = poll(poll_fds, poll_nfds, pending_ms);
|
||||
if (r != -1)
|
||||
break;
|
||||
error = SOCKERRNO;
|
||||
if ((error == EINVAL) || error_is_EINTR)
|
||||
break;
|
||||
if (timeout_ms > 0) {
|
||||
pending_ms = timeout_ms - elapsed_ms;
|
||||
if (pending_ms <= 0)
|
||||
break;
|
||||
}
|
||||
} while (r == -1);
|
||||
|
||||
if (r < 0)
|
||||
ret = -1;
|
||||
|
||||
if (r > 0) {
|
||||
ix = poll_nfds;
|
||||
while (ix--) {
|
||||
if (poll_fds[ix].revents & POLLNVAL) {
|
||||
SET_SOCKERRNO(EBADF);
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret) {
|
||||
ix = poll_nfds;
|
||||
while (ix--) {
|
||||
if (fds_read && (0 != FD_ISSET(poll_fds[ix].fd, fds_read))) {
|
||||
if (0 == (poll_fds[ix].revents & (POLLRDNORM|POLLERR|POLLHUP|POLLIN)))
|
||||
FD_CLR(poll_fds[ix].fd, fds_read);
|
||||
else
|
||||
ret++;
|
||||
}
|
||||
if (fds_write && (0 != FD_ISSET(poll_fds[ix].fd, fds_write))) {
|
||||
if (0 == (poll_fds[ix].revents & (POLLWRNORM|POLLERR|POLLHUP|POLLOUT)))
|
||||
FD_CLR(poll_fds[ix].fd, fds_write);
|
||||
else
|
||||
ret++;
|
||||
}
|
||||
if (fds_excep && (0 != FD_ISSET(poll_fds[ix].fd, fds_excep))) {
|
||||
if (0 == (poll_fds[ix].revents & (POLLRDBAND|POLLERR|POLLHUP|POLLPRI)))
|
||||
FD_CLR(poll_fds[ix].fd, fds_excep);
|
||||
else
|
||||
ret++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (poll_fds && (poll_nfds > SMALL_POLLNFDS))
|
||||
free(poll_fds);
|
||||
|
||||
#else /* HAVE_POLL_FINE */
|
||||
|
||||
VERIFY_NFDS(nfds);
|
||||
|
||||
ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
|
||||
|
||||
do {
|
||||
if (timeout_ms > 0) {
|
||||
pending_tv.tv_sec = pending_ms / 1000;
|
||||
pending_tv.tv_usec = (pending_ms % 1000) * 1000;
|
||||
}
|
||||
else if (!timeout_ms) {
|
||||
pending_tv.tv_sec = 0;
|
||||
pending_tv.tv_usec = 0;
|
||||
}
|
||||
r = select(nfds, fds_read, fds_write, fds_excep, ptimeout);
|
||||
if (r != -1)
|
||||
break;
|
||||
error = SOCKERRNO;
|
||||
if ((error == EINVAL) || (error == EBADF) || error_is_EINTR)
|
||||
break;
|
||||
if (timeout_ms > 0) {
|
||||
pending_ms = timeout_ms - elapsed_ms;
|
||||
if (pending_ms <= 0)
|
||||
break;
|
||||
}
|
||||
} while (r == -1);
|
||||
|
||||
if (r < 0)
|
||||
ret = -1;
|
||||
else
|
||||
ret = r;
|
||||
|
||||
#endif /* HAVE_POLL_FINE */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef TPF
|
||||
/*
|
||||
* This is a replacement for select() on the TPF platform.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue