wip to make easy_pollset dynamically resizing

This commit is contained in:
Stefan Eissing 2025-08-04 12:48:07 +02:00
parent 1a20a4a534
commit 436d7546eb
No known key found for this signature in database
15 changed files with 264 additions and 158 deletions

View file

@ -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);
}
/*

View file

@ -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;
}
/*

View file

@ -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

View file

@ -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

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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;

View file

@ -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
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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

View file

@ -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;
}

View file

@ -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,