mirror of
https://github.com/curl/curl.git
synced 2026-06-08 02:44:16 +03:00
wip to make easy_pollset dynamically resizing
This commit is contained in:
parent
1a20a4a534
commit
436d7546eb
15 changed files with 264 additions and 158 deletions
|
|
@ -277,11 +277,11 @@ static void async_ares_cleanup(struct Curl_easy *data)
|
|||
* (using curl_multi_fdset()) wants to get our fd_set setup.
|
||||
*/
|
||||
|
||||
unsigned int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||
CURLcode Curl_async_getsock(struct Curl_easy *data, struct easy_pollset *ps)
|
||||
{
|
||||
struct async_ares_ctx *ares = &data->state.async.ares;
|
||||
DEBUGASSERT(ares->channel);
|
||||
return Curl_ares_getsock(data, ares->channel, socks);
|
||||
return Curl_ares_getsock(data, ares->channel, ps);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -78,19 +78,38 @@
|
|||
* Returns: sockets-in-use-bitmap
|
||||
*/
|
||||
|
||||
unsigned int Curl_ares_getsock(struct Curl_easy *data,
|
||||
ares_channel channel,
|
||||
curl_socket_t *socks)
|
||||
|
||||
CURLcode Curl_ares_getsock(struct Curl_easy *data,
|
||||
ares_channel channel,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
|
||||
struct timeval timebuf;
|
||||
unsigned int max = ares_getsock(channel,
|
||||
(ares_socket_t *)socks,
|
||||
MAX_SOCKSPEREASYHANDLE);
|
||||
struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
|
||||
timediff_t milli = curlx_tvtoms(timeout);
|
||||
curl_socket_t sockets[5];
|
||||
unsigned int bitmap, i;
|
||||
struct timeval *timeout;
|
||||
timediff_t milli;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
bitmap = ares_getsock(channel, (ares_socket_t *)sockets,
|
||||
CURL_ARRAYSIZE(sockets));
|
||||
for(i = 0; i < CURL_ARRAYSIZE(sockets); ++i) {
|
||||
int flags = 0;
|
||||
if(ARES_GETSOCK_READABLE(bitmap, i))
|
||||
flags |= CURL_POLL_IN;
|
||||
if(ARES_GETSOCK_WRITABLE(bitmap, i))
|
||||
flags |= CURL_POLL_OUT;
|
||||
if(!flags)
|
||||
break;
|
||||
result = Curl_pollset_change(data, ps, sockets[i], flags, 0);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
||||
timeout = ares_timeout(channel, &maxtime, &timebuf);
|
||||
milli = curlx_tvtoms(timeout);
|
||||
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
|
||||
return max;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -630,33 +630,25 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
||||
CURLcode Curl_async_getsock(struct Curl_easy *data, struct easy_pollset *ps)
|
||||
{
|
||||
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
|
||||
unsigned int ret_val = 0;
|
||||
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
|
||||
int socketi = 0;
|
||||
#else
|
||||
(void)socks;
|
||||
#endif
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
#ifdef USE_HTTPSRR_ARES
|
||||
if(thrdd->rr.channel) {
|
||||
ret_val = Curl_ares_getsock(data, thrdd->rr.channel, socks);
|
||||
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
|
||||
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
|
||||
!ARES_GETSOCK_WRITABLE(ret_val, socketi))
|
||||
break;
|
||||
result = Curl_ares_getsock(data, thrdd->rr.channel, ps);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
if(!thrdd->addr)
|
||||
return ret_val;
|
||||
return result;
|
||||
|
||||
#ifndef CURL_DISABLE_SOCKETPAIR
|
||||
if(thrdd->addr) {
|
||||
/* return read fd to client for polling the DNS resolution status */
|
||||
socks[socketi] = thrdd->addr->sock_pair[0];
|
||||
ret_val |= GETSOCK_READSOCK(socketi);
|
||||
result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
@ -674,7 +666,7 @@ unsigned int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
|
|||
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef HAVE_GETADDRINFO
|
||||
|
|
|
|||
10
lib/asyn.h
10
lib/asyn.h
|
|
@ -37,6 +37,7 @@ struct Curl_dns_entry;
|
|||
struct addrinfo;
|
||||
struct hostent;
|
||||
struct connectdata;
|
||||
struct easy_pollset;
|
||||
|
||||
#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
|
||||
#error cannot have both CURLRES_ARES and CURLRES_THREADED defined
|
||||
|
|
@ -78,7 +79,7 @@ CURLcode Curl_async_get_impl(struct Curl_easy *easy, void **impl);
|
|||
* return bitmask indicating what file descriptors (referring to array indexes
|
||||
* in the 'sock' array) to wait for, read/write.
|
||||
*/
|
||||
unsigned int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *sock);
|
||||
CURLcode Curl_async_getsock(struct Curl_easy *data, struct easy_pollset *ps);
|
||||
|
||||
/*
|
||||
* Curl_async_is_resolved()
|
||||
|
|
@ -127,9 +128,10 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
|
|||
/* common functions for c-ares and threaded resolver with HTTPSRR */
|
||||
#include <ares.h>
|
||||
|
||||
unsigned int Curl_ares_getsock(struct Curl_easy *data,
|
||||
ares_channel channel,
|
||||
curl_socket_t *socks);
|
||||
CURLcode Curl_ares_getsock(struct Curl_easy *data,
|
||||
ares_channel channel,
|
||||
struct easy_pollset *ps);
|
||||
|
||||
int Curl_ares_perform(ares_channel channel,
|
||||
timediff_t timeout_ms);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -441,7 +441,7 @@ static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
|
|||
continue;
|
||||
Curl_conn_cf_adjust_pollset(b->cf, data, ps);
|
||||
}
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->n);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ static void cf_ip_happy_adjust_pollset(struct Curl_cfilter *cf,
|
|||
|
||||
if(!cf->connected) {
|
||||
cf_ip_ballers_pollset(&ctx->ballers, data, ps);
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
|
||||
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->n);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -469,6 +469,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
{
|
||||
#define CF_CONN_NUM_POLLS_ON_STACK 5
|
||||
struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
|
||||
struct easy_pollset ps;
|
||||
struct curl_pollfds cpfds;
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
|
@ -486,6 +487,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
if(*done)
|
||||
return CURLE_OK;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
|
||||
while(!*done) {
|
||||
if(Curl_conn_needs_flush(data, sockindex)) {
|
||||
|
|
@ -523,7 +525,6 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
/* check allowed time left */
|
||||
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
|
||||
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
|
||||
struct easy_pollset ps;
|
||||
int rc;
|
||||
|
||||
if(timeout_ms < 0) {
|
||||
|
|
@ -534,8 +535,8 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_pollfds_reset(&cpfds);
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
/* In general, we want to send after connect, wait on that. */
|
||||
if(sockfd != CURL_SOCKET_BAD)
|
||||
Curl_pollset_set_out_only(data, &ps, sockfd);
|
||||
|
|
@ -557,6 +558,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
out:
|
||||
Curl_pollset_cleanup(&ps);
|
||||
Curl_pollfds_cleanup(&cpfds);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -746,35 +748,17 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf,
|
|||
timediff_t timeout_ms)
|
||||
{
|
||||
struct easy_pollset ps;
|
||||
struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
|
||||
unsigned int i, npfds = 0;
|
||||
int result;
|
||||
|
||||
DEBUGASSERT(cf);
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->conn);
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
memset(pfds, 0, sizeof(pfds));
|
||||
Curl_pollset_init(&ps);
|
||||
|
||||
Curl_conn_cf_adjust_pollset(cf, data, &ps);
|
||||
DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
|
||||
for(i = 0; i < ps.num; ++i) {
|
||||
short events = 0;
|
||||
if(ps.actions[i] & CURL_POLL_IN) {
|
||||
events |= POLLIN;
|
||||
}
|
||||
if(ps.actions[i] & CURL_POLL_OUT) {
|
||||
events |= POLLOUT;
|
||||
}
|
||||
if(events) {
|
||||
pfds[npfds].fd = ps.sockets[i];
|
||||
pfds[npfds].events = events;
|
||||
++npfds;
|
||||
}
|
||||
}
|
||||
|
||||
if(!npfds)
|
||||
DEBUGF(infof(data, "no sockets to poll!"));
|
||||
return Curl_poll(pfds, npfds, timeout_ms);
|
||||
result = Curl_pollset_poll(data, &ps, timeout_ms);
|
||||
Curl_pollset_cleanup(&ps);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
|
||||
|
|
|
|||
|
|
@ -486,18 +486,19 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
|
|||
{
|
||||
if(Curl_llist_head(&cshutdn->list)) {
|
||||
struct Curl_llist_node *e;
|
||||
struct easy_pollset ps;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
for(e = Curl_llist_head(&cshutdn->list); e;
|
||||
e = Curl_node_next(e)) {
|
||||
struct easy_pollset ps;
|
||||
unsigned int i;
|
||||
struct connectdata *conn = Curl_node_elem(e);
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_attach_connection(data, conn);
|
||||
Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
Curl_detach_connection(data);
|
||||
|
||||
for(i = 0; i < ps.num; i++) {
|
||||
for(i = 0; i < ps.n; i++) {
|
||||
#ifdef __DJGPP__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warith-conversion"
|
||||
|
|
@ -514,6 +515,7 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
|
|||
*maxfd = (int)ps.sockets[i];
|
||||
}
|
||||
}
|
||||
Curl_pollset_cleanup(&ps);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -529,16 +531,18 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
|
|||
struct easy_pollset ps;
|
||||
struct connectdata *conn;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
for(e = Curl_llist_head(&cshutdn->list); e;
|
||||
e = Curl_node_next(e)) {
|
||||
conn = Curl_node_elem(e);
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_attach_connection(data, conn);
|
||||
Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
Curl_detach_connection(data);
|
||||
|
||||
need += Curl_waitfds_add_ps(cwfds, &ps);
|
||||
}
|
||||
Curl_pollset_cleanup(&ps);
|
||||
}
|
||||
return need;
|
||||
}
|
||||
|
|
@ -554,20 +558,23 @@ CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
|
|||
struct easy_pollset ps;
|
||||
struct connectdata *conn;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
for(e = Curl_llist_head(&cshutdn->list); e;
|
||||
e = Curl_node_next(e)) {
|
||||
conn = Curl_node_elem(e);
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
Curl_pollset_reset(&ps);
|
||||
Curl_attach_connection(data, conn);
|
||||
Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
Curl_detach_connection(data);
|
||||
|
||||
result = Curl_pollfds_add_ps(cpfds, &ps);
|
||||
if(result) {
|
||||
Curl_pollset_cleanup(&ps);
|
||||
Curl_pollfds_cleanup(cpfds);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
Curl_pollset_cleanup(&ps);
|
||||
}
|
||||
out:
|
||||
return result;
|
||||
|
|
|
|||
10
lib/hostip.c
10
lib/hostip.c
|
|
@ -1523,21 +1523,21 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
|
|||
}
|
||||
#endif
|
||||
|
||||
unsigned int Curl_resolv_getsock(struct Curl_easy *data,
|
||||
curl_socket_t *socks)
|
||||
CURLcode Curl_resolv_getsock(struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
{
|
||||
#ifdef CURLRES_ASYNCH
|
||||
#ifndef CURL_DISABLE_DOH
|
||||
if(data->conn->bits.doh)
|
||||
/* nothing to wait for during DoH resolve, those handles have their own
|
||||
sockets */
|
||||
return GETSOCK_BLANK;
|
||||
return CURLE_OK;
|
||||
#endif
|
||||
return Curl_async_getsock(data, socks);
|
||||
return Curl_async_getsock(data, ps);
|
||||
#else
|
||||
(void)data;
|
||||
(void)socks;
|
||||
return GETSOCK_BLANK;
|
||||
return CURLE_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ struct addrinfo;
|
|||
struct hostent;
|
||||
struct Curl_easy;
|
||||
struct connectdata;
|
||||
struct easy_pollset;
|
||||
|
||||
enum alpnid {
|
||||
ALPN_none = 0,
|
||||
|
|
@ -199,8 +200,8 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
|
|||
#else
|
||||
#define Curl_resolv_check(x,y) CURLE_NOT_BUILT_IN
|
||||
#endif
|
||||
unsigned int Curl_resolv_getsock(struct Curl_easy *data,
|
||||
curl_socket_t *socks);
|
||||
CURLcode Curl_resolv_getsock(struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
|
||||
CURLcode Curl_resolver_error(struct Curl_easy *data);
|
||||
|
||||
|
|
|
|||
43
lib/multi.c
43
lib/multi.c
|
|
@ -1012,18 +1012,20 @@ static unsigned int perform_getsock(struct Curl_easy *data,
|
|||
|
||||
/* Initializes `poll_set` with the current socket poll actions needed
|
||||
* for transfer `data`. */
|
||||
void Curl_multi_getsock(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
const char *caller)
|
||||
CURLMcode Curl_multi_getsock(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
const char *caller)
|
||||
{
|
||||
CURLMcode mresult = CURLM_OK;
|
||||
CURLcode result = CURLE_OK;
|
||||
bool expect_sockets = TRUE;
|
||||
|
||||
/* If the transfer has no connection, this is fine. Happens when
|
||||
called via curl_multi_remove_handle() => Curl_multi_ev_assess() =>
|
||||
Curl_multi_getsock(). */
|
||||
Curl_pollset_reset(data, ps);
|
||||
Curl_pollset_reset(ps);
|
||||
if(!data->conn)
|
||||
return;
|
||||
return CURLM_OK;
|
||||
|
||||
switch(data->mstate) {
|
||||
case MSTATE_INIT:
|
||||
|
|
@ -1035,7 +1037,7 @@ void Curl_multi_getsock(struct Curl_easy *data,
|
|||
break;
|
||||
|
||||
case MSTATE_RESOLVING:
|
||||
Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
|
||||
result = Curl_resolv_getsock(data, ps);
|
||||
/* connection filters are not involved in this phase. It's ok if we get no
|
||||
* sockets to wait for. Resolving can wake up from other sources. */
|
||||
expect_sockets = FALSE;
|
||||
|
|
@ -1089,6 +1091,13 @@ void Curl_multi_getsock(struct Curl_easy *data,
|
|||
break;
|
||||
}
|
||||
|
||||
if(result) {
|
||||
if(result == CURLE_OUT_OF_MEMORY)
|
||||
mresult = CURLM_OUT_OF_MEMORY;
|
||||
else
|
||||
mresult = CURLM_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Unblocked and waiting to receive with buffered input.
|
||||
* Make transfer run again at next opportunity. */
|
||||
|
|
@ -1102,7 +1111,7 @@ void Curl_multi_getsock(struct Curl_easy *data,
|
|||
Curl_multi_mark_dirty(data);
|
||||
}
|
||||
|
||||
switch(ps->num) {
|
||||
switch(ps->n) {
|
||||
case 0:
|
||||
CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)",
|
||||
caller, Curl_llist_count(&data->state.timeoutlist),
|
||||
|
|
@ -1129,10 +1138,10 @@ void Curl_multi_getsock(struct Curl_easy *data,
|
|||
break;
|
||||
default:
|
||||
CURL_TRC_M(data, "%s pollset[fds=%u], timeouts=%zu",
|
||||
caller, ps->num, Curl_llist_count(&data->state.timeoutlist));
|
||||
caller, ps->n, Curl_llist_count(&data->state.timeoutlist));
|
||||
break;
|
||||
}
|
||||
if(expect_sockets && !ps->num && data->multi &&
|
||||
if(expect_sockets && !ps->n && data->multi &&
|
||||
!Curl_uint_bset_contains(&data->multi->dirty, data->mid) &&
|
||||
!Curl_llist_count(&data->state.timeoutlist) &&
|
||||
!Curl_cwriter_is_paused(data) && !Curl_creader_is_paused(data) &&
|
||||
|
|
@ -1145,6 +1154,8 @@ void Curl_multi_getsock(struct Curl_easy *data,
|
|||
infof(data, "WARNING: no socket in pollset or timer, transfer may stall!");
|
||||
DEBUGASSERT(0);
|
||||
}
|
||||
out:
|
||||
return mresult;
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_fdset(CURLM *m,
|
||||
|
|
@ -1156,6 +1167,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
|
|||
and then we must make sure that is done. */
|
||||
int this_max_fd = -1;
|
||||
struct Curl_multi *multi = m;
|
||||
struct easy_pollset ps;
|
||||
unsigned int i, mid;
|
||||
(void)exc_fd_set; /* not used */
|
||||
|
||||
|
|
@ -1165,10 +1177,10 @@ CURLMcode curl_multi_fdset(CURLM *m,
|
|||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
if(Curl_uint_bset_first(&multi->process, &mid)) {
|
||||
do {
|
||||
struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
|
||||
struct easy_pollset ps;
|
||||
|
||||
if(!data) {
|
||||
DEBUGASSERT(0);
|
||||
|
|
@ -1176,7 +1188,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
|
|||
}
|
||||
|
||||
Curl_multi_getsock(data, &ps, "curl_multi_fdset");
|
||||
for(i = 0; i < ps.num; i++) {
|
||||
for(i = 0; i < ps.n; i++) {
|
||||
if(!FDSET_SOCK(ps.sockets[i]))
|
||||
/* pretend it does not exist */
|
||||
continue;
|
||||
|
|
@ -1202,6 +1214,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
|
|||
read_fd_set, write_fd_set, &this_max_fd);
|
||||
|
||||
*max_fd = this_max_fd;
|
||||
Curl_pollset_cleanup(&ps);
|
||||
|
||||
return CURLM_OK;
|
||||
}
|
||||
|
|
@ -1214,6 +1227,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
|
|||
struct Curl_waitfds cwfds;
|
||||
CURLMcode result = CURLM_OK;
|
||||
struct Curl_multi *multi = m;
|
||||
struct easy_pollset ps;
|
||||
unsigned int need = 0, mid;
|
||||
|
||||
if(!ufds && (size || !fd_count))
|
||||
|
|
@ -1225,11 +1239,11 @@ CURLMcode curl_multi_waitfds(CURLM *m,
|
|||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
Curl_waitfds_init(&cwfds, ufds, size);
|
||||
if(Curl_uint_bset_first(&multi->process, &mid)) {
|
||||
do {
|
||||
struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
|
||||
struct easy_pollset ps;
|
||||
if(!data) {
|
||||
DEBUGASSERT(0);
|
||||
Curl_uint_bset_remove(&multi->process, mid);
|
||||
|
|
@ -1250,6 +1264,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
|
|||
|
||||
if(fd_count)
|
||||
*fd_count = need;
|
||||
Curl_pollset_cleanup(&ps);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1283,6 +1298,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
|||
struct curltime expire_time;
|
||||
long timeout_internal;
|
||||
int retcode = 0;
|
||||
struct easy_pollset ps;
|
||||
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
|
||||
struct curl_pollfds cpfds;
|
||||
unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
|
||||
|
|
@ -1307,12 +1323,12 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
|||
if(timeout_ms < 0)
|
||||
return CURLM_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
Curl_pollset_init(&ps);
|
||||
Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
|
||||
|
||||
/* Add the curl handles to our pollfds first */
|
||||
if(Curl_uint_bset_first(&multi->process, &mid)) {
|
||||
do {
|
||||
struct easy_pollset ps;
|
||||
data = Curl_multi_get_easy(multi, mid);
|
||||
if(!data) {
|
||||
DEBUGASSERT(0);
|
||||
|
|
@ -1519,6 +1535,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
|
|||
}
|
||||
|
||||
out:
|
||||
Curl_pollset_cleanup(&ps);
|
||||
Curl_pollfds_cleanup(&cpfds);
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
|
|||
DEBUGASSERT(prev_ps);
|
||||
|
||||
/* Handle changes to sockets the transfer is interested in. */
|
||||
for(i = 0; i < ps->num; i++) {
|
||||
for(i = 0; i < ps->n; i++) {
|
||||
unsigned char last_action;
|
||||
bool first_time = FALSE; /* data/conn appears first time on socket */
|
||||
|
||||
|
|
@ -362,7 +362,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
|
|||
entry->conn ? 1 : 0);
|
||||
}
|
||||
else {
|
||||
for(j = 0; j < prev_ps->num; j++) {
|
||||
for(j = 0; j < prev_ps->n; j++) {
|
||||
if(s == prev_ps->sockets[j]) {
|
||||
last_action = prev_ps->actions[j];
|
||||
break;
|
||||
|
|
@ -377,11 +377,11 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
|
|||
}
|
||||
|
||||
/* Handle changes to sockets the transfer is NO LONGER interested in. */
|
||||
for(i = 0; i < prev_ps->num; i++) {
|
||||
for(i = 0; i < prev_ps->n; i++) {
|
||||
bool stillused = FALSE;
|
||||
|
||||
s = prev_ps->sockets[i];
|
||||
for(j = 0; j < ps->num; j++) {
|
||||
for(j = 0; j < ps->n; j++) {
|
||||
if(s == ps->sockets[j]) {
|
||||
/* socket is still supervised */
|
||||
stillused = TRUE;
|
||||
|
|
@ -443,9 +443,11 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
|
|||
|
||||
static void mev_pollset_dtor(void *key, size_t klen, void *entry)
|
||||
{
|
||||
struct easy_pollset *ps = entry;
|
||||
(void)key;
|
||||
(void)klen;
|
||||
free(entry);
|
||||
Curl_pollset_cleanup(ps);
|
||||
free(ps);
|
||||
}
|
||||
|
||||
static struct easy_pollset*
|
||||
|
|
@ -456,6 +458,7 @@ mev_add_new_conn_pollset(struct connectdata *conn)
|
|||
ps = calloc(1, sizeof(*ps));
|
||||
if(!ps)
|
||||
return NULL;
|
||||
Curl_pollset_init(ps);
|
||||
if(Curl_conn_meta_set(conn, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor))
|
||||
return NULL;
|
||||
return ps;
|
||||
|
|
@ -469,6 +472,7 @@ mev_add_new_xfer_pollset(struct Curl_easy *data)
|
|||
ps = calloc(1, sizeof(*ps));
|
||||
if(!ps)
|
||||
return NULL;
|
||||
Curl_pollset_init(ps);
|
||||
if(Curl_meta_set(data, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor))
|
||||
return NULL;
|
||||
return ps;
|
||||
|
|
@ -486,42 +490,41 @@ mev_get_last_pollset(struct Curl_easy *data,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void mev_init_cur_pollset(struct easy_pollset *ps,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
memset(ps, 0, sizeof(*ps));
|
||||
if(conn)
|
||||
Curl_conn_adjust_pollset(data, conn, ps);
|
||||
else if(data)
|
||||
Curl_multi_getsock(data, ps, "ev assess");
|
||||
}
|
||||
|
||||
static CURLMcode mev_assess(struct Curl_multi *multi,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn)
|
||||
{
|
||||
if(multi && multi->socket_cb) {
|
||||
struct easy_pollset ps, *last_ps;
|
||||
struct easy_pollset ps, *last_ps;
|
||||
CURLMcode res = CURLM_OK;
|
||||
|
||||
mev_init_cur_pollset(&ps, data, conn);
|
||||
last_ps = mev_get_last_pollset(data, conn);
|
||||
if(!multi || !multi->socket_cb)
|
||||
return CURLM_OK;
|
||||
|
||||
if(!last_ps && ps.num) {
|
||||
if(conn)
|
||||
last_ps = mev_add_new_conn_pollset(conn);
|
||||
else
|
||||
last_ps = mev_add_new_xfer_pollset(data);
|
||||
if(!last_ps)
|
||||
return CURLM_OUT_OF_MEMORY;
|
||||
}
|
||||
Curl_pollset_init(&ps);
|
||||
if(conn)
|
||||
Curl_conn_adjust_pollset(data, conn, &ps);
|
||||
else if(data)
|
||||
Curl_multi_getsock(data, &ps, "ev assess");
|
||||
last_ps = mev_get_last_pollset(data, conn);
|
||||
|
||||
if(last_ps)
|
||||
return mev_pollset_diff(multi, data, conn, &ps, last_ps);
|
||||
if(!last_ps && ps.n) {
|
||||
if(conn)
|
||||
last_ps = mev_add_new_conn_pollset(conn);
|
||||
else
|
||||
DEBUGASSERT(!ps.num);
|
||||
last_ps = mev_add_new_xfer_pollset(data);
|
||||
if(!last_ps) {
|
||||
res = CURLM_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
return CURLM_OK;
|
||||
|
||||
if(last_ps)
|
||||
res = mev_pollset_diff(multi, data, conn, &ps, last_ps);
|
||||
else
|
||||
DEBUGASSERT(!ps.n);
|
||||
out:
|
||||
Curl_pollset_cleanup(&ps);
|
||||
return res;
|
||||
}
|
||||
|
||||
CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
|
|||
/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
|
||||
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
|
||||
|
||||
void Curl_multi_getsock(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
const char *caller);
|
||||
CURLMcode Curl_multi_getsock(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
const char *caller);
|
||||
|
||||
/**
|
||||
* Borrow the transfer buffer from the multi, suitable
|
||||
|
|
|
|||
126
lib/select.c
126
lib/select.c
|
|
@ -41,6 +41,7 @@
|
|||
#include "urldata.h"
|
||||
#include "connect.h"
|
||||
#include "select.h"
|
||||
#include "curl_trc.h"
|
||||
#include "curlx/timediff.h"
|
||||
#include "curlx/wait.h"
|
||||
#include "curlx/warnless.h"
|
||||
|
|
@ -423,7 +424,7 @@ CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
|
|||
|
||||
DEBUGASSERT(cpfds);
|
||||
DEBUGASSERT(ps);
|
||||
for(i = 0; i < ps->num; i++) {
|
||||
for(i = 0; i < ps->n; i++) {
|
||||
short events = 0;
|
||||
if(ps->actions[i] & CURL_POLL_IN)
|
||||
events |= POLLIN;
|
||||
|
|
@ -481,7 +482,7 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds,
|
|||
|
||||
DEBUGASSERT(cwfds);
|
||||
DEBUGASSERT(ps);
|
||||
for(i = 0; i < ps->num; i++) {
|
||||
for(i = 0; i < ps->n; i++) {
|
||||
short events = 0;
|
||||
if(ps->actions[i] & CURL_POLL_IN)
|
||||
events |= CURL_WAIT_POLLIN;
|
||||
|
|
@ -493,48 +494,70 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds,
|
|||
return need;
|
||||
}
|
||||
|
||||
void Curl_pollset_reset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps)
|
||||
void Curl_pollset_reset(struct easy_pollset *ps)
|
||||
{
|
||||
size_t i;
|
||||
(void)data;
|
||||
memset(ps, 0, sizeof(*ps));
|
||||
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++)
|
||||
unsigned int i;
|
||||
ps->n = 0;
|
||||
#ifdef DEBUGBUILD
|
||||
DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
|
||||
#endif
|
||||
DEBUGASSERT(ps->count);
|
||||
for(i = 0; i < ps->count; i++)
|
||||
ps->sockets[i] = CURL_SOCKET_BAD;
|
||||
memset(ps->actions, 0, ps->count * sizeof(ps->actions[0]));
|
||||
}
|
||||
|
||||
void Curl_pollset_init(struct easy_pollset *ps)
|
||||
{
|
||||
memset(ps, 0, sizeof(*ps));
|
||||
#ifdef DEBUGBUILD
|
||||
ps->init = CURL_EASY_POLLSET_MAGIC;
|
||||
#endif
|
||||
ps->count = MAX_SOCKSPEREASYHANDLE;
|
||||
Curl_pollset_reset(ps);
|
||||
}
|
||||
|
||||
void Curl_pollset_cleanup(struct easy_pollset *ps)
|
||||
{
|
||||
Curl_pollset_reset(ps);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void Curl_pollset_change(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
int add_flags, int remove_flags)
|
||||
CURLcode Curl_pollset_change(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
int add_flags, int remove_flags)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
|
||||
#endif
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(VALID_SOCK(sock));
|
||||
if(!VALID_SOCK(sock))
|
||||
return;
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
|
||||
DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
|
||||
DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
|
||||
for(i = 0; i < ps->num; ++i) {
|
||||
for(i = 0; i < ps->n; ++i) {
|
||||
if(ps->sockets[i] == sock) {
|
||||
ps->actions[i] &= (unsigned char)(~remove_flags);
|
||||
ps->actions[i] |= (unsigned char)add_flags;
|
||||
/* all gone? remove socket */
|
||||
if(!ps->actions[i]) {
|
||||
if((i + 1) < ps->num) {
|
||||
if((i + 1) < ps->n) {
|
||||
memmove(&ps->sockets[i], &ps->sockets[i + 1],
|
||||
(ps->num - (i + 1)) * sizeof(ps->sockets[0]));
|
||||
(ps->n - (i + 1)) * sizeof(ps->sockets[0]));
|
||||
memmove(&ps->actions[i], &ps->actions[i + 1],
|
||||
(ps->num - (i + 1)) * sizeof(ps->actions[0]));
|
||||
(ps->n - (i + 1)) * sizeof(ps->actions[0]));
|
||||
}
|
||||
--ps->num;
|
||||
--ps->n;
|
||||
}
|
||||
return;
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
/* not present */
|
||||
|
|
@ -547,24 +570,65 @@ void Curl_pollset_change(struct Curl_easy *data,
|
|||
* The current maximum in practise is HTTP/3 eyeballing where
|
||||
* we have up to 4 sockets involved in connection setup.
|
||||
*/
|
||||
DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
|
||||
if(i < MAX_SOCKSPEREASYHANDLE) {
|
||||
DEBUGASSERT(i < ps->count);
|
||||
if(i < ps->count) {
|
||||
ps->sockets[i] = sock;
|
||||
ps->actions[i] = (unsigned char)add_flags;
|
||||
ps->num = i + 1;
|
||||
ps->n = i + 1;
|
||||
}
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
void Curl_pollset_set(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
bool do_in, bool do_out)
|
||||
CURLcode Curl_pollset_set(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
bool do_in, bool do_out)
|
||||
{
|
||||
Curl_pollset_change(data, ps, sock,
|
||||
(do_in ? CURL_POLL_IN : 0)|
|
||||
(do_out ? CURL_POLL_OUT : 0),
|
||||
(!do_in ? CURL_POLL_IN : 0)|
|
||||
(!do_out ? CURL_POLL_OUT : 0));
|
||||
return Curl_pollset_change(data, ps, sock,
|
||||
(do_in ? CURL_POLL_IN : 0)|
|
||||
(do_out ? CURL_POLL_OUT : 0),
|
||||
(!do_in ? CURL_POLL_IN : 0)|
|
||||
(!do_out ? CURL_POLL_OUT : 0));
|
||||
}
|
||||
|
||||
int Curl_pollset_poll(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
timediff_t timeout_ms)
|
||||
{
|
||||
struct pollfd *pfds;
|
||||
unsigned int i, npfds;
|
||||
int result;
|
||||
|
||||
(void)data;
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->conn);
|
||||
|
||||
if(!ps->n)
|
||||
return curlx_wait_ms(timeout_ms);
|
||||
|
||||
pfds = calloc(ps->n, sizeof(*pfds));
|
||||
if(!pfds)
|
||||
return -1;
|
||||
|
||||
npfds = 0;
|
||||
for(i = 0; i < ps->n; ++i) {
|
||||
short events = 0;
|
||||
if(ps->actions[i] & CURL_POLL_IN) {
|
||||
events |= POLLIN;
|
||||
}
|
||||
if(ps->actions[i] & CURL_POLL_OUT) {
|
||||
events |= POLLOUT;
|
||||
}
|
||||
if(events) {
|
||||
pfds[npfds].fd = ps->sockets[i];
|
||||
pfds[npfds].events = events;
|
||||
++npfds;
|
||||
}
|
||||
}
|
||||
|
||||
result = Curl_poll(pfds, npfds, timeout_ms);
|
||||
free(pfds);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
|
||||
|
|
@ -609,7 +673,7 @@ void Curl_pollset_check(struct Curl_easy *data,
|
|||
|
||||
(void)data;
|
||||
DEBUGASSERT(VALID_SOCK(sock));
|
||||
for(i = 0; i < ps->num; ++i) {
|
||||
for(i = 0; i < ps->n; ++i) {
|
||||
if(ps->sockets[i] == sock) {
|
||||
*pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
|
||||
*pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
|
||||
|
|
@ -625,7 +689,7 @@ bool Curl_pollset_want_read(struct Curl_easy *data,
|
|||
{
|
||||
unsigned int i;
|
||||
(void)data;
|
||||
for(i = 0; i < ps->num; ++i) {
|
||||
for(i = 0; i < ps->n; ++i) {
|
||||
if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
35
lib/select.h
35
lib/select.h
|
|
@ -133,27 +133,39 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms);
|
|||
/* Polling requested by an easy handle.
|
||||
* `action` is CURL_POLL_IN, CURL_POLL_OUT or CURL_POLL_INOUT.
|
||||
*/
|
||||
#ifdef DEBUGBUILD
|
||||
#define CURL_EASY_POLLSET_MAGIC 0x7a657370
|
||||
#endif
|
||||
|
||||
struct easy_pollset {
|
||||
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
|
||||
unsigned int num;
|
||||
unsigned int n;
|
||||
unsigned int count;
|
||||
#ifdef DEBUGBUILD
|
||||
int init;
|
||||
#endif
|
||||
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
|
||||
};
|
||||
|
||||
void Curl_pollset_reset(struct Curl_easy *data,
|
||||
struct easy_pollset *ps);
|
||||
/* Initialize before first use */
|
||||
void Curl_pollset_init(struct easy_pollset *ps);
|
||||
/* Free any allocated resources */
|
||||
void Curl_pollset_cleanup(struct easy_pollset *ps);
|
||||
/* Reset to an empty pollset */
|
||||
void Curl_pollset_reset(struct easy_pollset *ps);
|
||||
|
||||
/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for
|
||||
* socket `sock`. If the socket is not already part of the poll set, it
|
||||
* will be added.
|
||||
* If the socket is present and all poll flags are cleared, it will be removed.
|
||||
*/
|
||||
void Curl_pollset_change(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
int add_flags, int remove_flags);
|
||||
CURLcode Curl_pollset_change(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
int add_flags, int remove_flags);
|
||||
|
||||
void Curl_pollset_set(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
bool do_in, bool do_out);
|
||||
CURLcode Curl_pollset_set(struct Curl_easy *data,
|
||||
struct easy_pollset *ps, curl_socket_t sock,
|
||||
bool do_in, bool do_out);
|
||||
|
||||
#define Curl_pollset_add_in(data, ps, sock) \
|
||||
Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0)
|
||||
|
|
@ -169,6 +181,11 @@ void Curl_pollset_set(struct Curl_easy *data,
|
|||
Curl_pollset_change((data), (ps), (sock), \
|
||||
CURL_POLL_OUT, CURL_POLL_IN)
|
||||
|
||||
/* return < = on error, 0 on timeout or how many sockets are ready */
|
||||
int Curl_pollset_poll(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
timediff_t timeout_ms);
|
||||
|
||||
void Curl_pollset_add_socks(struct Curl_easy *data,
|
||||
struct easy_pollset *ps,
|
||||
unsigned int (*socks_cb)(struct Curl_easy *data,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue