From 743096a4964bf921f7b39cc7b739fd4fab6ad39c Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Wed, 12 Aug 2026 15:49:39 +0200 Subject: [PATCH] uint-bset: add slot0 member Add a fixed slot0 member for uint32_bset to have no allocations for sizes < 64. This is a common use case for curl_easy_perform(). Closes #22561 --- lib/multi.c | 2 ++ lib/uint-bset.c | 21 +++++++++++++++------ lib/uint-bset.h | 1 + tests/unit/unit3211.c | 5 +++++ 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/multi.c b/lib/multi.c index dd4b9bfe8a..013aefc63f 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -432,6 +432,8 @@ static CURLMcode multi_xfers_add(struct Curl_multi *multi, /* make it a 64 multiple, since our bitsets grow by that and * small (easy_multi) grows to at least 64 on first resize. */ new_size = (((used + min_unused) + 63) / 64) * 64; + if(new_size < 256) /* don't be too shy about it */ + new_size = 256; } } } diff --git a/lib/uint-bset.c b/lib/uint-bset.c index 55aedb234b..f734f86ffd 100644 --- a/lib/uint-bset.c +++ b/lib/uint-bset.c @@ -44,14 +44,22 @@ CURLcode Curl_uint32_bset_resize(struct uint32_bset *bset, uint32_t nmax) DEBUGASSERT(bset->init == CURL_UINT32_BSET_MAGIC); if(nslots != bset->nslots) { - uint64_t *slots = curlx_calloc(nslots, sizeof(uint64_t)); - if(!slots) - return CURLE_OUT_OF_MEMORY; + uint64_t *slots; + if(nslots > 1) { + slots = curlx_calloc(nslots, sizeof(uint64_t)); + if(!slots) + return CURLE_OUT_OF_MEMORY; + } + else { + bset->slot0 = 0; + slots = &bset->slot0; + } - if(bset->slots) { + if((bset->slots != slots) && nslots && bset->nslots) { memcpy(slots, bset->slots, (CURLMIN(nslots, bset->nslots) * sizeof(uint64_t))); - curlx_free(bset->slots); + if(bset->slots != &bset->slot0) + curlx_free(bset->slots); } bset->slots = slots; bset->nslots = nslots; @@ -63,7 +71,8 @@ CURLcode Curl_uint32_bset_resize(struct uint32_bset *bset, uint32_t nmax) void Curl_uint32_bset_destroy(struct uint32_bset *bset) { DEBUGASSERT(bset->init == CURL_UINT32_BSET_MAGIC); - curlx_free(bset->slots); + if(bset->slots != &bset->slot0) + curlx_free(bset->slots); memset(bset, 0, sizeof(*bset)); } diff --git a/lib/uint-bset.h b/lib/uint-bset.h index ce0450c53c..d4e2972ad1 100644 --- a/lib/uint-bset.h +++ b/lib/uint-bset.h @@ -39,6 +39,7 @@ struct uint32_bset { uint64_t *slots; + uint64_t slot0; uint32_t nslots; uint32_t first_slot_used; #ifdef DEBUGBUILD diff --git a/tests/unit/unit3211.c b/tests/unit/unit3211.c index 0d1dde200d..fea99301a1 100644 --- a/tests/unit/unit3211.c +++ b/tests/unit/unit3211.c @@ -126,6 +126,10 @@ static CURLcode test_unit3211(const char *arg) { UNITTEST_BEGIN_SIMPLE + static const uint32_t s0[] = { + /* spread numbers, some at slot edges */ + 0, 1, 4, 5, 8, 13, 17, 23, 24, 63, + }; static const uint32_t s1[] = { /* spread numbers, some at slot edges */ 0, 1, 4, 17, 63, 64, 65, 66, 90, 99, @@ -142,6 +146,7 @@ static CURLcode test_unit3211(const char *arg) 120, 121, 122, 123, 124, 125, 126, 127, }; + check_set("s0", 64, s0, CURL_ARRAYSIZE(s1)); check_set("s1", 100, s1, CURL_ARRAYSIZE(s1)); check_set("s2", 1000, s2, CURL_ARRAYSIZE(s2));