← Commit list

38703fe261

Stefan Eissing
Stefan Eissing
2026-09-03
SUCCESS Duration: 400s

Subject

multihandle: some easy shrinks

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

lib/multi.c+45 -36
@@ -3345,6 +3345,7 @@ CURLMcode curl_multi_setopt(CURLM *m, CURLMoption option, ...)
struct Curl_multi *multi = m;
va_list param;
unsigned long uarg;
+ size_t szarg;
va_start(param, option);
@@ -3372,16 +3373,20 @@ CURLMcode curl_multi_setopt(CURLM *m, CURLMoption option, ...)
break;
case CURLMOPT_MAXCONNECTS:
uarg = va_arg(param, unsigned long);
- if(uarg <= UINT_MAX)
- multi->maxconnects = (unsigned int)uarg;
+ if(uarg <= UINT32_MAX)
+ multi->maxconnects = (uint32_t)uarg;
break;
case CURLMOPT_MAX_HOST_CONNECTIONS:
- if(!curlx_sltouz(va_arg(param, long), &multi->max_host_connections))
+ if(!curlx_sltouz(va_arg(param, long), &szarg))
mresult = CURLM_BAD_FUNCTION_ARGUMENT;
+ multi->max_host_connections = (szarg < UINT32_MAX) ?
+ (uint32_t)szarg : UINT32_MAX;
break;
case CURLMOPT_MAX_TOTAL_CONNECTIONS:
- if(!curlx_sltouz(va_arg(param, long), &multi->max_total_connections))
+ if(!curlx_sltouz(va_arg(param, long), &szarg))
mresult = CURLM_BAD_FUNCTION_ARGUMENT;
+ multi->max_total_connections = (szarg < UINT32_MAX) ?
+ (uint32_t)szarg : UINT32_MAX;
break;
/* options formerly used for pipelining */
case CURLMOPT_MAX_PIPELINE_LENGTH:
@@ -3395,10 +3400,12 @@ CURLMcode curl_multi_setopt(CURLM *m, CURLMoption option, ...)
case CURLMOPT_PIPELINING_SERVER_BL:
break;
case CURLMOPT_MAX_CONCURRENT_STREAMS: {
- long streams = va_arg(param, long);
- if((streams < 1) || (streams > INT_MAX))
- streams = 100;
- multi->max_concurrent_streams = (unsigned int)streams;
+ if(!curlx_sltouz(va_arg(param, long), &szarg) ||
+ !szarg || (szarg > (size_t)INT_MAX)) /* preserve previous cutoff */
+ multi->max_concurrent_streams = 100;
+ else
+ multi->max_concurrent_streams = (szarg < UINT32_MAX) ?
+ (uint32_t)szarg : UINT32_MAX;
break;
}
case CURLMOPT_NETWORK_CHANGED: {
@@ -3906,7 +3913,7 @@ static void multi_schedule_pending(struct Curl_multi *multi)
}
}
-unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
+uint32_t Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
{
DEBUGASSERT(multi);
return multi->max_concurrent_streams;
@@ -3991,6 +3998,17 @@ out:
return mresult;
}
+static struct Curl_fixed_buf *fixed_buf_create(size_t len)
+{
+ struct Curl_fixed_buf *fbuf;
+ if((SIZE_MAX - sizeof(*fbuf)) < len)
+ return NULL; /* too large */
+ fbuf = curlx_malloc(len + sizeof(*fbuf));
+ if(fbuf)
+ fbuf->len = len;
+ return fbuf;
+}
+
CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
char **pbuf, size_t *pbuflen)
{
@@ -4012,25 +4030,24 @@ CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
}
if(data->multi->xfer_buf &&
- data->set.buffer_size > data->multi->xfer_buf_len) {
+ data->set.buffer_size > data->multi->xfer_buf->len) {
/* not large enough, get a new one */
curlx_safefree(data->multi->xfer_buf);
- data->multi->xfer_buf_len = 0;
}
if(!data->multi->xfer_buf) {
- data->multi->xfer_buf = curlx_malloc(curlx_uitouz(data->set.buffer_size));
+ data->multi->xfer_buf =
+ fixed_buf_create(curlx_uitouz(data->set.buffer_size));
if(!data->multi->xfer_buf) {
failf(data, "could not allocate xfer_buf of %u bytes",
data->set.buffer_size);
return CURLE_OUT_OF_MEMORY;
}
- data->multi->xfer_buf_len = data->set.buffer_size;
}
data->multi->xfer_buf_borrowed = TRUE;
- *pbuf = data->multi->xfer_buf;
- *pbuflen = data->multi->xfer_buf_len;
+ *pbuf = data->multi->xfer_buf->data;
+ *pbuflen = data->multi->xfer_buf->len;
return CURLE_OK;
}
@@ -4039,7 +4056,8 @@ void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
(void)buf;
DEBUGASSERT(data);
DEBUGASSERT(data->multi);
- DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
+ DEBUGASSERT(!buf || (data->multi->xfer_buf &&
+ data->multi->xfer_buf->data == buf));
data->multi->xfer_buf_borrowed = FALSE;
}
@@ -4054,36 +4072,30 @@ CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
failf(data, "transfer has no multi handle");
return CURLE_FAILED_INIT;
}
- if(!data->set.upload_buffer_size) {
- failf(data, "transfer upload buffer size is 0");
- return CURLE_FAILED_INIT;
- }
if(data->multi->xfer_ulbuf_borrowed) {
failf(data, "attempt to borrow xfer_ulbuf when already borrowed");
return CURLE_AGAIN;
}
if(data->multi->xfer_ulbuf &&
- data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
+ data->set.upload_buffer_size > data->multi->xfer_ulbuf->len) {
/* not large enough, get a new one */
curlx_safefree(data->multi->xfer_ulbuf);
- data->multi->xfer_ulbuf_len = 0;
}
if(!data->multi->xfer_ulbuf) {
data->multi->xfer_ulbuf =
- curlx_malloc(curlx_uitouz(data->set.upload_buffer_size));
+ fixed_buf_create(curlx_uitouz(data->set.upload_buffer_size));
if(!data->multi->xfer_ulbuf) {
failf(data, "could not allocate xfer_ulbuf of %u bytes",
data->set.upload_buffer_size);
return CURLE_OUT_OF_MEMORY;
}
- data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
}
data->multi->xfer_ulbuf_borrowed = TRUE;
- *pbuf = data->multi->xfer_ulbuf;
- *pbuflen = data->multi->xfer_ulbuf_len;
+ *pbuf = data->multi->xfer_ulbuf->data;
+ *pbuflen = data->multi->xfer_ulbuf->len;
return CURLE_OK;
}
@@ -4092,7 +4104,8 @@ void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf)
(void)buf;
DEBUGASSERT(data);
DEBUGASSERT(data->multi);
- DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
+ DEBUGASSERT(!buf || (data->multi->xfer_ulbuf &&
+ data->multi->xfer_ulbuf->data == buf));
data->multi->xfer_ulbuf_borrowed = FALSE;
}
@@ -4112,23 +4125,21 @@ CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
return CURLE_AGAIN;
}
- if(data->multi->xfer_sockbuf && blen > data->multi->xfer_sockbuf_len) {
+ if(data->multi->xfer_sockbuf && blen > data->multi->xfer_sockbuf->len) {
/* not large enough, get a new one */
curlx_safefree(data->multi->xfer_sockbuf);
- data->multi->xfer_sockbuf_len = 0;
}
if(!data->multi->xfer_sockbuf) {
- data->multi->xfer_sockbuf = curlx_malloc(blen);
+ data->multi->xfer_sockbuf = fixed_buf_create(blen);
if(!data->multi->xfer_sockbuf) {
failf(data, "could not allocate xfer_sockbuf of %zu bytes", blen);
return CURLE_OUT_OF_MEMORY;
}
- data->multi->xfer_sockbuf_len = blen;
}
data->multi->xfer_sockbuf_borrowed = TRUE;
- *pbuf = data->multi->xfer_sockbuf;
+ *pbuf = data->multi->xfer_sockbuf->data;
return CURLE_OK;
}
@@ -4141,7 +4152,8 @@ void Curl_multi_xfer_sockbuf_release(struct Curl_easy *data, char *buf)
curlx_free(buf);
}
else {
- DEBUGASSERT(!buf || data->multi->xfer_sockbuf == buf);
+ DEBUGASSERT(!buf || (data->multi->xfer_sockbuf &&
+ data->multi->xfer_sockbuf->data == buf));
data->multi->xfer_sockbuf_borrowed = FALSE;
}
}
@@ -4150,13 +4162,10 @@ static void multi_xfer_bufs_free(struct Curl_multi *multi)
{
DEBUGASSERT(multi);
curlx_safefree(multi->xfer_buf);
- multi->xfer_buf_len = 0;
multi->xfer_buf_borrowed = FALSE;
curlx_safefree(multi->xfer_ulbuf);
- multi->xfer_ulbuf_len = 0;
multi->xfer_ulbuf_borrowed = FALSE;
curlx_safefree(multi->xfer_sockbuf);
- multi->xfer_sockbuf_len = 0;
multi->xfer_sockbuf_borrowed = FALSE;
}
lib/multihandle.h+21 -26
@@ -84,6 +84,11 @@ typedef enum {
/* value for MAXIMUM CONCURRENT STREAMS upper limit */
#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
+struct Curl_fixed_buf {
+ size_t len; /* the allocated data length */
+ char data[1]; /* the actual buffer */
+};
+
/* This is the struct known as CURLM on the outside */
struct Curl_multi {
/* First a simple identifier to more easily detect if a user mixes up
@@ -95,6 +100,7 @@ struct Curl_multi {
uint32_t xfers_really_alive; /* amount of added transfers that have
passed INIT state but are not COMPLETE yet */
uint32_t max_concurrent_streams;
+ curl_off_t xfers_total_ever; /* total of added transfers, ever. */
struct uint32_tbl xfers; /* transfers added to this multi */
/* Each transfer's mid may be present in at most one of these */
@@ -105,9 +111,12 @@ struct Curl_multi {
struct Curl_mapi_stack callstack; /* multi api calls ongoing */
- struct Curl_llist msglist; /* a list of messages from completed transfers */
+ /* current time for transfers running in this multi handle */
+ struct curltime now;
+ /* expiration times for all attached easy handles */
+ struct Curl_timeouts timeouts;
- curl_off_t xfers_total_ever; /* total of added transfers, ever. */
+ struct Curl_llist msglist; /* a list of messages from completed transfers */
struct Curl_easy *admin; /* internal easy handle for admin operations.
gets assigned `mid` 0 on multi init */
@@ -131,20 +140,9 @@ struct Curl_multi {
struct PslCache psl;
#endif
- /* current time for transfers running in this multi handle */
- struct curltime now;
- /* expiration times for all attached easy handles */
- struct Curl_timeouts timeouts;
-
- /* buffer used for transfer data, lazy initialized */
- char *xfer_buf; /* the actual buffer */
- size_t xfer_buf_len; /* the allocated length */
- /* buffer used for upload data, lazy initialized */
- char *xfer_ulbuf; /* the actual buffer */
- size_t xfer_ulbuf_len; /* the allocated length */
- /* buffer used for socket I/O operations, lazy initialized */
- char *xfer_sockbuf; /* the actual buffer */
- size_t xfer_sockbuf_len; /* the allocated length */
+ struct Curl_fixed_buf *xfer_buf; /* transfer downloads, lazy */
+ struct Curl_fixed_buf *xfer_ulbuf; /* transfer uploads, lazy */
+ struct Curl_fixed_buf *xfer_sockbuf; /* transfer socket I/O, lazy */
/* multi event related things */
struct curl_multi_ev ev;
@@ -161,17 +159,13 @@ struct Curl_multi {
struct cshutdn cshutdn; /* connection shutdown handling */
struct cpool cpool; /* connection pool (bundles) */
- timediff_t last_expire_offset_us; /* times offset of last expiry */
- size_t max_host_connections; /* if >0, a fixed limit of the maximum number
- of connections per host */
- size_t max_total_connections; /* if >0, a fixed limit of the maximum number
- of connections in total */
+ timediff_t last_expire_offset_us; /* times offset of last expiry */
/* timer callback and user data pointer for the *socket() API */
curl_multi_timer_callback timer_cb;
void *timer_userp;
- int last_timeout_ms; /* the last timeout value set via timer_cb */
+ timediff_t last_timeout_ms; /* the last timeout value set via timer_cb */
#ifdef USE_WINSOCK
WSAEVENT wsa_event; /* Winsock event used for waits */
@@ -187,12 +181,13 @@ struct Curl_multi {
for write. Used for internal wakeups,
e.g. threaded resolver. */
#endif
- unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of
+ uint32_t max_host_connections; /* if >0, a fixed limit of the maximum number
+ of connections per host */
+ uint32_t max_total_connections; /* if >0, a fixed limit of the maximum number
+ of connections in total */
+ uint32_t maxconnects; /* if >0, a fixed limit of the maximum number of
entries we are allowed to grow the connection
cache to */
-#ifdef DEBUGBUILD
- unsigned int now_access_count;
-#endif
uint32_t last_pending_mid; /* mid of last pending transfer rescheduled */
uint32_t last_resolv_id; /* id of the last DNS resolve operation */
BIT(ipv6_works);
lib/multiif.h+1 -1
@@ -73,7 +73,7 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
struct connectdata *conn);
/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
-unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
+uint32_t Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
CURLMcode Curl_multi_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
lib/url.c+1 -1
@@ -2357,7 +2357,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data,
CURL_TRC_M(data, "Allowing sub-requests (like DoH) to override "
"max connection limit");
else {
- infof(data, "No connections available, total of %zu reached.",
+ infof(data, "No connections available, total of %u reached.",
data->multi->max_total_connections);
result = CURLE_NO_CONNECTION_AVAILABLE;
goto out;
lib/vquic/cf-ngtcp2.c+4 -2
@@ -1053,8 +1053,10 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
max_streams += avail_bidi_streams;
*pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
}
- else /* transport params not arrived yet? take our default. */
- *pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
+ else { /* transport params not arrived yet? take our default. */
+ uint32_t n = Curl_multi_max_concurrent_streams(data->multi);
+ *pres1 = (n < INT_MAX) ? (int)n : INT_MAX;
+ }
CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
"MAX_CONCURRENT -> %d (%u in use)",
cf->conn->connection_id, *pres1, cf->conn->attached_xfers);