if(CONN_INUSE(conn) && !aborted) {
CURL_TRC_M(data, "[CPOOL] not discarding #%" FMT_OFF_T
" still in use by %u transfers", conn->connection_id,
- CONN_ATTACHED(conn));
+ conn->attached_xfers);
return;
}
* are other users of it */
if(CONN_INUSE(conn) && !aborted) {
DEBUGASSERT(0); /* does this ever happen? */
- DEBUGF(infof(data, "Curl_disconnect when inuse: %u", CONN_ATTACHED(conn)));
+ DEBUGF(infof(data, "conn terminate when inuse: %u", conn->attached_xfers));
return;
}
CF_DATA_SAVE(save, cf, data);
if(!ctx->h2 || !nghttp2_session_check_request_allowed(ctx->h2)) {
/* the limit is what we have in use right now */
- effective_max = CONN_ATTACHED(cf->conn);
+ effective_max = cf->conn->attached_xfers;
}
else {
effective_max = ctx->max_concurrent_streams;
Curl_detach_connection(data);
- CURL_TRC_M(data, "multi_done_locked, in use=%u",
- Curl_uint32_spbset_count(&conn->xfers_attached));
+ CURL_TRC_M(data, "multi_done_locked, in use=%u", conn->attached_xfers);
if(CONN_INUSE(conn)) {
/* Stop if still used. */
CURL_TRC_M(data, "Connection still in use %u, no more multi_done now!",
- Curl_uint32_spbset_count(&conn->xfers_attached));
+ conn->attached_xfers);
return;
}
{
struct connectdata *conn = data->conn;
if(conn) {
- Curl_uint32_spbset_remove(&conn->xfers_attached, data->mid);
- if(Curl_uint32_spbset_empty(&conn->xfers_attached))
- conn->attached_multi = NULL;
+ /* this should never happen, prevent underflow */
+ DEBUGASSERT(conn->attached_xfers);
+ if(conn->attached_xfers) {
+ conn->attached_xfers--;
+ if(!conn->attached_xfers)
+ conn->attached_multi = NULL;
+ }
}
data->conn = NULL;
}
DEBUGASSERT(data);
DEBUGASSERT(!data->conn);
DEBUGASSERT(conn);
+ DEBUGASSERT(conn->attached_xfers < UINT32_MAX);
data->conn = conn;
- Curl_uint32_spbset_add(&conn->xfers_attached, data->mid);
+ conn->attached_xfers++;
/* all attached transfers must be from the same multi */
if(!conn->attached_multi)
conn->attached_multi = data->multi;
return n;
}
-bool Curl_uint32_spbset_empty(struct uint32_spbset *bset)
-{
- struct uint32_spbset_chunk *chunk;
- uint32_t i;
-
- for(chunk = &bset->head; chunk; chunk = chunk->next) {
- for(i = 0; i < CURL_UINT32_SPBSET_CH_SLOTS; ++i) {
- if(chunk->slots[i])
- return FALSE;
- }
- }
- return TRUE;
-}
-
UNITTEST void Curl_uint32_spbset_clear(struct uint32_spbset *bset)
{
struct uint32_spbset_chunk *next, *chunk;
/* Get the cardinality of the bitset, e.g. numbers present in the set. */
uint32_t Curl_uint32_spbset_count(struct uint32_spbset *bset);
-/* TRUE of bitset is empty */
-bool Curl_uint32_spbset_empty(struct uint32_spbset *bset);
-
/* Add the number `i` to the bitset.
* Numbers can be added more than once, without making a difference.
* Returns FALSE if allocations failed. */
Curl_safefree(conn->unix_domain_socket);
#endif
Curl_safefree(conn->destination);
- Curl_uint32_spbset_destroy(&conn->xfers_attached);
Curl_hash_destroy(&conn->meta_hash);
curlx_free(conn); /* free all the connection oriented data */
if(CONN_INUSE(conn) && m->may_multiplex) {
DEBUGASSERT(conn->bits.multiplex);
/* If multiplexed, make sure we do not go over concurrency limit */
- if(CONN_ATTACHED(conn) >=
+ if(conn->attached_xfers >=
Curl_multi_max_concurrent_streams(m->data->multi)) {
infof(m->data, "client side MAX_CONCURRENT_STREAMS reached"
- ", skip (%u)", CONN_ATTACHED(conn));
+ ", skip (%u)", conn->attached_xfers);
return FALSE;
}
- if(CONN_ATTACHED(conn) >=
+ if(conn->attached_xfers >=
Curl_conn_get_max_concurrent(m->data, conn, FIRSTSOCKET)) {
infof(m->data, "MAX_CONCURRENT_STREAMS reached, skip (%u)",
- CONN_ATTACHED(conn));
+ conn->attached_xfers);
return FALSE;
}
/* When not multiplexed, we have a match here! */
conn->recv_idx = 0; /* default for receiving transfer data */
conn->send_idx = 0; /* default for sending transfer data */
conn->connection_id = -1; /* no ID */
+ conn->attached_xfers = 0;
conn->remote_port = -1; /* unknown at this point */
/* Store creation time to help future close decision making */
conn->connect_only = data->set.connect_only;
conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
- /* Initialize the attached xfers bitset */
- Curl_uint32_spbset_init(&conn->xfers_attached);
-
/* Store the local bind parameters that will be used for this connection */
if(data->set.str[STRING_DEVICE]) {
conn->localdev = curlx_strdup(data->set.str[STRING_DEVICE]);
DEBUGASSERT(conn);
Curl_pgrsTime(data, TIMER_POSTQUEUE);
if(reused) {
- if(CONN_ATTACHED(conn) > 1)
+ if(conn->attached_xfers > 1)
/* multiplexed */
*protocol_done = TRUE;
}
handle is still used by one or more easy handles and can only used by any
other easy handle without careful consideration (== only for
multiplexing) and it cannot be used by another multi handle! */
-#define CONN_INUSE(c) (!Curl_uint32_spbset_empty(&(c)->xfers_attached))
-#define CONN_ATTACHED(c) Curl_uint32_spbset_count(&(c)->xfers_attached)
+#define CONN_INUSE(c) (!!(c)->attached_xfers)
/**** Fields set when inited and not modified again */
curl_off_t connection_id; /* Contains a unique number to make it easier to
was used on this connection. */
struct curltime keepalive;
- struct uint32_spbset xfers_attached; /* mids of attached transfers */
/* A connection cache from a SHARE might be used in several multi handles.
* We MUST not reuse connections that are running in another multi,
* for concurrency reasons. That multi might run in another thread.
int remote_port; /* the remote port, not the proxy port! */
int conn_to_port; /* the remote port to connect to. valid only if
bits.conn_to_port is set */
+
+ uint32_t attached_xfers; /* # of attached easy handles */
+
#ifdef USE_IPV6
unsigned int scope_id; /* Scope id for IPv6 */
#endif
}
else if(ctx->max_bidi_streams) {
uint64_t avail_bidi_streams = 0;
- uint64_t max_streams = CONN_ATTACHED(cf->conn);
+ uint64_t max_streams = cf->conn->attached_xfers;
if(ctx->max_bidi_streams > ctx->used_bidi_streams)
avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
max_streams += avail_bidi_streams;
*pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
"MAX_CONCURRENT -> %d (%u in use)",
- cf->conn->connection_id, *pres1, CONN_ATTACHED(cf->conn));
+ cf->conn->connection_id, *pres1, cf->conn->attached_xfers);
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
}
return CURLE_HTTP3;
}
/* we report avail + in_use */
- v += CONN_ATTACHED(cf->conn);
+ v += cf->conn->attached_xfers;
*pres1 = (v > INT_MAX) ? INT_MAX : (int)v;
#else
*pres1 = 100;
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
- uint64_t max_streams = CONN_ATTACHED(cf->conn);
+ uint64_t max_streams = cf->conn->attached_xfers;
if(!ctx->goaway && ctx->qconn) {
max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
}
*pres1 = (max_streams > INT_MAX) ? INT_MAX : (int)max_streams;
CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
"MAX_CONCURRENT -> %d (%u in use)",
- cf->conn->connection_id, *pres1, CONN_ATTACHED(cf->conn));
+ cf->conn->connection_id, *pres1, cf->conn->attached_xfers);
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS: