From: Stefan Eissing Date: Sun, 23 Feb 2025 11:20:17 +0000 (+0100) Subject: hash_offt: standalone hash for curl_off_t X-Git-Tag: curl-8_13_0~309 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1aa69221be42ed7acad2b1c9ca62fd9832077796;p=thirdparty%2Fcurl.git hash_offt: standalone hash for curl_off_t Add a standalong hash table for curl_offt_t as key. This allows a smaller memory footprint and faster lookups as we do not need to deal with variable key lengths. Use in all places we had the standard hash for this purpose. Closes #16442 --- diff --git a/lib/Makefile.inc b/lib/Makefile.inc index cb48733ae7..543b4d4ca6 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -164,6 +164,7 @@ LIB_CFILES = \ getinfo.c \ gopher.c \ hash.c \ + hash_offt.c \ headers.c \ hmac.c \ hostasyn.c \ @@ -312,6 +313,7 @@ LIB_HFILES = \ getinfo.h \ gopher.h \ hash.h \ + hash_offt.h \ headers.h \ hostip.h \ hsts.h \ diff --git a/lib/hash.c b/lib/hash.c index a710e53935..680b938621 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -400,25 +400,3 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter) return iter->current; } - -void Curl_hash_offt_init(struct Curl_hash *h, - size_t slots, - Curl_hash_dtor dtor) -{ - Curl_hash_init(h, slots, Curl_hash_str, Curl_str_key_compare, dtor); -} - -void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem) -{ - return Curl_hash_add(h, &id, sizeof(id), elem); -} - -int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id) -{ - return Curl_hash_delete(h, &id, sizeof(id)); -} - -void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id) -{ - return Curl_hash_pick(h, &id, sizeof(id)); -} diff --git a/lib/hash.h b/lib/hash.h index 20680a9da5..f429c76ccf 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -108,13 +108,4 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter); void Curl_hash_print(struct Curl_hash *h, void (*func)(void *)); -/* Hash for `curl_off_t` as key */ -void Curl_hash_offt_init(struct Curl_hash *h, size_t slots, - Curl_hash_dtor dtor); - -void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem); -int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id); -void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id); - - #endif /* HEADER_CURL_HASH_H */ diff --git a/lib/hash_offt.c b/lib/hash_offt.c new file mode 100644 index 0000000000..2edc81af16 --- /dev/null +++ b/lib/hash_offt.c @@ -0,0 +1,242 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "hash_offt.h" +#include "curl_memory.h" + +/* The last #include file should be: */ +#include "memdebug.h" + +/* random patterns for API verification */ +#ifdef DEBUGBUILD +#define CURL_HASHOFFTINIT 0x7117e781 +#endif + +static size_t hash_offt_hash(curl_off_t id, size_t slots) +{ + return (size_t)((id >= 0) ? (id % slots) : (-id % slots)); +} + +struct Curl_hash_offt_entry { + curl_off_t id; + struct Curl_hash_offt_entry *next; + void *value; +}; + +void Curl_hash_offt_init(struct Curl_hash_offt *h, + size_t slots, + Curl_hash_offt_dtor *dtor) +{ + DEBUGASSERT(h); + DEBUGASSERT(slots); + + h->table = NULL; + h->dtor = dtor; + h->size = 0; + h->slots = slots; +#ifdef DEBUGBUILD + h->init = CURL_HASHOFFTINIT; +#endif +} + +static struct Curl_hash_offt_entry * +hash_offt_mk_entry(curl_off_t id, void *value) +{ + struct Curl_hash_offt_entry *e; + + /* allocate the struct for the hash entry */ + e = malloc(sizeof(*e)); + if(e) { + e->id = id; + e->next = NULL; + e->value = value; + } + return e; +} + +static void hash_offt_entry_clear(struct Curl_hash_offt *h, + struct Curl_hash_offt_entry *e) +{ + DEBUGASSERT(h); + DEBUGASSERT(e); + if(e->value) { + if(h->dtor) + h->dtor(e->id, e->value); + e->value = NULL; + } +} + +static void hash_offt_entry_destroy(struct Curl_hash_offt *h, + struct Curl_hash_offt_entry *e) +{ + hash_offt_entry_clear(h, e); + free(e); +} + +static void hash_offt_entry_unlink(struct Curl_hash_offt *h, + struct Curl_hash_offt_entry **he_anchor, + struct Curl_hash_offt_entry *he) +{ + *he_anchor = he->next; + --h->size; +} + +static void hash_offtr_elem_link(struct Curl_hash_offt *h, + struct Curl_hash_offt_entry **he_anchor, + struct Curl_hash_offt_entry *he) +{ + he->next = *he_anchor; + *he_anchor = he; + ++h->size; +} + +#define CURL_HASH_OFFT_SLOT(h,id) h->table[hash_offt_hash(id, h->slots)] +#define CURL_HASH_OFFT_SLOT_ADDR(h,id) &CURL_HASH_OFFT_SLOT(h,id) + +bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value) +{ + struct Curl_hash_offt_entry *he, **slot; + + DEBUGASSERT(h); + DEBUGASSERT(h->slots); + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + if(!h->table) { + h->table = calloc(h->slots, sizeof(*he)); + if(!h->table) + return FALSE; /* OOM */ + } + + slot = CURL_HASH_OFFT_SLOT_ADDR(h, id); + for(he = *slot; he; he = he->next) { + if(he->id == id) { + /* existing key entry, overwrite by clearing old pointer */ + hash_offt_entry_clear(h, he); + he->value = value; + return TRUE; + } + } + + he = hash_offt_mk_entry(id, value); + if(!he) + return FALSE; /* OOM */ + + hash_offtr_elem_link(h, slot, he); + return TRUE; +} + +bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id) +{ + DEBUGASSERT(h); + DEBUGASSERT(h->slots); + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + if(h->table) { + struct Curl_hash_offt_entry *he, **he_anchor; + + he_anchor = CURL_HASH_OFFT_SLOT_ADDR(h, id); + while(*he_anchor) { + he = *he_anchor; + if(id == he->id) { + hash_offt_entry_unlink(h, he_anchor, he); + hash_offt_entry_destroy(h, he); + return TRUE; + } + he_anchor = &he->next; + } + } + return FALSE; +} + +void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id) +{ + DEBUGASSERT(h); + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + if(h->table) { + struct Curl_hash_offt_entry *he; + DEBUGASSERT(h->slots); + he = CURL_HASH_OFFT_SLOT(h, id); + while(he) { + if(id == he->id) { + return he->value; + } + he = he->next; + } + } + return NULL; +} + +void Curl_hash_offt_clear(struct Curl_hash_offt *h) +{ + if(h && h->table) { + struct Curl_hash_offt_entry *he, **he_anchor; + size_t i; + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + for(i = 0; i < h->slots; ++i) { + he_anchor = &h->table[i]; + while(*he_anchor) { + he = *he_anchor; + hash_offt_entry_unlink(h, he_anchor, he); + hash_offt_entry_destroy(h, he); + } + } + } +} + +void +Curl_hash_offt_destroy(struct Curl_hash_offt *h) +{ + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + if(h->table) { + Curl_hash_offt_clear(h); + Curl_safefree(h->table); + } + DEBUGASSERT(h->size == 0); + h->slots = 0; +} + +size_t Curl_hash_offt_count(struct Curl_hash_offt *h) +{ + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + return h->size; +} + +void Curl_hash_offt_visit(struct Curl_hash_offt *h, + Curl_hash_offt_visit_cb *cb, + void *user_data) +{ + if(h && h->table && cb) { + struct Curl_hash_offt_entry *he; + size_t i; + DEBUGASSERT(h->init == CURL_HASHOFFTINIT); + for(i = 0; i < h->slots; ++i) { + for(he = h->table[i]; he; he = he->next) { + if(!cb(he->id, he->value, user_data)) + return; + } + } + } +} diff --git a/lib/hash_offt.h b/lib/hash_offt.h new file mode 100644 index 0000000000..02cbec1ea9 --- /dev/null +++ b/lib/hash_offt.h @@ -0,0 +1,67 @@ +#ifndef HEADER_CURL_HASH_OFFT_H +#define HEADER_CURL_HASH_OFFT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#include + +#include "llist.h" + +struct Curl_hash_offt_entry; +typedef void Curl_hash_offt_dtor(curl_off_t id, void *value); + +/* Hash for `curl_off_t` as key */ +struct Curl_hash_offt { + struct Curl_hash_offt_entry **table; + Curl_hash_offt_dtor *dtor; + size_t slots; + size_t size; +#ifdef DEBUGBUILD + int init; +#endif +}; + +void Curl_hash_offt_init(struct Curl_hash_offt *h, + size_t slots, + Curl_hash_offt_dtor *dtor); +void Curl_hash_offt_destroy(struct Curl_hash_offt *h); + +bool Curl_hash_offt_set(struct Curl_hash_offt *h, curl_off_t id, void *value); +bool Curl_hash_offt_remove(struct Curl_hash_offt *h, curl_off_t id); +void *Curl_hash_offt_get(struct Curl_hash_offt *h, curl_off_t id); +void Curl_hash_offt_clear(struct Curl_hash_offt *h); +size_t Curl_hash_offt_count(struct Curl_hash_offt *h); + + +typedef bool Curl_hash_offt_visit_cb(curl_off_t id, void *value, + void *user_data); + +void Curl_hash_offt_visit(struct Curl_hash_offt *h, + Curl_hash_offt_visit_cb *cb, + void *user_data); + + +#endif /* HEADER_CURL_HASH_OFFT_H */ diff --git a/lib/http2.c b/lib/http2.c index c7ad2652bf..45436ff83a 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -29,7 +29,7 @@ #include #include "urldata.h" #include "bufq.h" -#include "hash.h" +#include "hash_offt.h" #include "http1.h" #include "http2.h" #include "http.h" @@ -135,7 +135,7 @@ struct cf_h2_ctx { struct bufc_pool stream_bufcp; /* spares for stream buffers */ struct dynbuf scratch; /* scratch buffer for temp use */ - struct Curl_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */ + struct Curl_hash_offt streams; /* hash of `data->mid` to `h2_stream_ctx` */ size_t drain_total; /* sum of all stream's UrlState drain */ uint32_t max_concurrent_streams; uint32_t goaway_error; /* goaway error code from server */ @@ -155,7 +155,7 @@ struct cf_h2_ctx { #define CF_CTX_CALL_DATA(cf) \ ((struct cf_h2_ctx *)(cf)->ctx)->call_data -static void h2_stream_hash_free(void *stream); +static void h2_stream_hash_free(curl_off_t id, void *stream); static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade) { @@ -176,8 +176,7 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx) Curl_bufq_free(&ctx->outbufq); Curl_bufcp_free(&ctx->stream_bufcp); Curl_dyn_free(&ctx->scratch); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); + Curl_hash_offt_destroy(&ctx->streams); memset(ctx, 0, sizeof(*ctx)); } free(ctx); @@ -267,8 +266,9 @@ static void h2_stream_ctx_free(struct h2_stream_ctx *stream) free(stream); } -static void h2_stream_hash_free(void *stream) +static void h2_stream_hash_free(curl_off_t id, void *stream) { + (void)id; DEBUGASSERT(stream); h2_stream_ctx_free((struct h2_stream_ctx *)stream); } diff --git a/lib/multi_ev.c b/lib/multi_ev.c index 64a810e1b1..110f37a130 100644 --- a/lib/multi_ev.c +++ b/lib/multi_ev.c @@ -54,8 +54,8 @@ static void mev_in_callback(struct Curl_multi *multi, bool value) * what to supervise (CURL_POLL_IN/CURL_POLL_OUT/CURL_POLL_REMOVE) */ struct mev_sh_entry { - struct Curl_hash xfers; /* hash of transfers using this socket */ - struct Curl_hash conns; /* hash of connections using this socket */ + struct Curl_hash_offt xfers; /* hash of transfers using this socket */ + struct Curl_hash_offt conns; /* hash of connections using this socket */ void *user_data; /* libcurl app data via curl_multi_assign() */ unsigned int action; /* CURL_POLL_IN/CURL_POLL_OUT we last told the * libcurl application to watch out for */ @@ -81,8 +81,8 @@ static size_t mev_sh_entry_compare(void *k1, size_t k1_len, static void mev_sh_entry_dtor(void *freethis) { struct mev_sh_entry *entry = (struct mev_sh_entry *)freethis; - Curl_hash_destroy(&entry->xfers); - Curl_hash_destroy(&entry->conns); + Curl_hash_offt_destroy(&entry->xfers); + Curl_hash_offt_destroy(&entry->conns); free(entry); } @@ -97,11 +97,6 @@ mev_sh_entry_get(struct Curl_hash *sh, curl_socket_t s) return NULL; } -static void mev_nop_dtor(void *e) -{ - (void)e; /* does nothing */ -} - /* make sure this socket is present in the hash for this handle */ static struct mev_sh_entry * mev_sh_entry_add(struct Curl_hash *sh, curl_socket_t s) @@ -119,8 +114,8 @@ mev_sh_entry_add(struct Curl_hash *sh, curl_socket_t s) if(!check) return NULL; /* major failure */ - Curl_hash_offt_init(&check->xfers, CURL_MEV_XFER_HASH_SIZE, mev_nop_dtor); - Curl_hash_offt_init(&check->conns, CURL_MEV_CONN_HASH_SIZE, mev_nop_dtor); + Curl_hash_offt_init(&check->xfers, CURL_MEV_XFER_HASH_SIZE, NULL); + Curl_hash_offt_init(&check->conns, CURL_MEV_CONN_HASH_SIZE, NULL); /* make/add new hash entry */ if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) { @@ -139,7 +134,7 @@ static void mev_sh_entry_kill(struct Curl_multi *multi, curl_socket_t s) static size_t mev_sh_entry_user_count(struct mev_sh_entry *e) { - return Curl_hash_count(&e->xfers) + Curl_hash_count(&e->conns); + return Curl_hash_offt_count(&e->xfers) + Curl_hash_offt_count(&e->conns); } static bool mev_sh_entry_xfer_known(struct mev_sh_entry *e, @@ -174,7 +169,7 @@ static bool mev_sh_entry_conn_add(struct mev_sh_entry *e, static bool mev_sh_entry_xfer_remove(struct mev_sh_entry *e, struct Curl_easy *data) { - return !Curl_hash_offt_remove(&e->xfers, data->id); + return Curl_hash_offt_remove(&e->xfers, data->id); } /* Purge any information about socket `s`. @@ -341,8 +336,8 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, ", total=%zu/%zu (xfer/conn)", s, conn ? "connection" : "transfer", conn ? conn->connection_id : data->id, - Curl_hash_count(&entry->xfers), - Curl_hash_count(&entry->conns)); + Curl_hash_offt_count(&entry->xfers), + Curl_hash_offt_count(&entry->conns)); } else { for(j = 0; j < prev_ps->num; j++) { @@ -399,8 +394,8 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, return mresult; CURL_TRC_M(data, "ev entry fd=%" FMT_SOCKET_T ", removed transfer, " "total=%zu/%zu (xfer/conn)", s, - Curl_hash_count(&entry->xfers), - Curl_hash_count(&entry->conns)); + Curl_hash_offt_count(&entry->xfers), + Curl_hash_offt_count(&entry->conns)); } else { mresult = mev_forget_socket(multi, data, s, "last user gone"); @@ -415,7 +410,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, } static struct easy_pollset* -mev_add_new_pollset(struct Curl_hash *h, curl_off_t id) +mev_add_new_pollset(struct Curl_hash_offt *h, curl_off_t id) { struct easy_pollset *ps; @@ -522,6 +517,20 @@ CURLMcode Curl_multi_ev_assign(struct Curl_multi *multi, return CURLM_OK; } +static bool mev_xfer_expire_cb(curl_off_t id, void *value, void *user_data) +{ + const struct curltime *nowp = user_data; + struct Curl_easy *data = value; + + DEBUGASSERT(data); + DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER); + if(data && id >= 0) { + /* Expire with out current now, so we will get it below when + * asking the splaytree for expired transfers. */ + Curl_expire_ex(data, nowp, 0, EXPIRE_RUN_NOW); + } + return TRUE; +} void Curl_multi_ev_expire_xfers(struct Curl_multi *multi, curl_socket_t s, @@ -539,24 +548,9 @@ void Curl_multi_ev_expire_xfers(struct Curl_multi *multi, asked to get removed, so thus we better survive stray socket actions and just move on. */ if(entry) { - struct Curl_hash_iterator iter; - struct Curl_hash_element *he; - - /* the socket can be shared by many transfers, iterate */ - Curl_hash_start_iterate(&entry->xfers, &iter); - for(he = Curl_hash_next_element(&iter); he; - he = Curl_hash_next_element(&iter)) { - struct Curl_easy *data = (struct Curl_easy *)he->ptr; - DEBUGASSERT(data); - DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER); - DEBUGASSERT(data->id >= 0); /* we should not track internal handles */ - - /* Expire with out current now, so we will get it below when - * asking the splaytree for expired transfers. */ - Curl_expire_ex(data, nowp, 0, EXPIRE_RUN_NOW); - } + Curl_hash_offt_visit(&entry->xfers, mev_xfer_expire_cb, (void *)nowp); - if(Curl_hash_count(&entry->conns)) + if(Curl_hash_offt_count(&entry->conns)) *run_cpool = TRUE; } } @@ -587,8 +581,9 @@ void Curl_multi_ev_conn_done(struct Curl_multi *multi, #define CURL_MEV_PS_HASH_SLOTS (991) /* nice prime */ -static void mev_hash_pollset_free(void *entry) +static void mev_hash_pollset_free(curl_off_t id, void *entry) { + (void)id; free(entry); } @@ -605,6 +600,6 @@ void Curl_multi_ev_init(struct Curl_multi *multi, size_t hashsize) void Curl_multi_ev_cleanup(struct Curl_multi *multi) { Curl_hash_destroy(&multi->ev.sh_entries); - Curl_hash_destroy(&multi->ev.xfer_pollsets); - Curl_hash_destroy(&multi->ev.conn_pollsets); + Curl_hash_offt_destroy(&multi->ev.xfer_pollsets); + Curl_hash_offt_destroy(&multi->ev.conn_pollsets); } diff --git a/lib/multi_ev.h b/lib/multi_ev.h index f0745db29e..20e052e003 100644 --- a/lib/multi_ev.h +++ b/lib/multi_ev.h @@ -24,14 +24,17 @@ * ***************************************************************************/ +#include "hash.h" +#include "hash_offt.h" + struct Curl_easy; struct Curl_multi; struct easy_pollset; struct curl_multi_ev { struct Curl_hash sh_entries; - struct Curl_hash xfer_pollsets; - struct Curl_hash conn_pollsets; + struct Curl_hash_offt xfer_pollsets; + struct Curl_hash_offt conn_pollsets; }; /* Setup/teardown of multi event book-keeping. */ diff --git a/lib/urldata.h b/lib/urldata.h index 0f6278e201..c2b50e6fe9 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -159,6 +159,7 @@ typedef unsigned int curl_prot_t; #include "http_chunks.h" /* for the structs and enum stuff */ #include "hostip.h" #include "hash.h" +#include "hash_offt.h" #include "splay.h" #include "dynbuf.h" #include "dynhds.h" diff --git a/lib/vquic/curl_msh3.c b/lib/vquic/curl_msh3.c index 8f23e90ece..a4bffbeb72 100644 --- a/lib/vquic/curl_msh3.c +++ b/lib/vquic/curl_msh3.c @@ -28,6 +28,7 @@ #include "urldata.h" #include "hash.h" +#include "hash_offt.h" #include "timeval.h" #include "multiif.h" #include "sendf.h" @@ -119,7 +120,7 @@ struct cf_msh3_ctx { struct cf_call_data call_data; struct curltime connect_started; /* time the current attempt started */ struct curltime handshake_at; /* time connect handshake finished */ - struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */ + struct Curl_hash_offt streams; /* hash `data->mid` to `stream_ctx` */ /* Flags written by msh3/msquic thread */ bool handshake_complete; bool handshake_succeeded; @@ -130,7 +131,7 @@ struct cf_msh3_ctx { BIT(active); }; -static void h3_stream_hash_free(void *stream); +static void h3_stream_hash_free(curl_off_t id, void *stream); static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx, const struct Curl_addrinfo *ai) @@ -154,7 +155,7 @@ static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx, static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx) { if(ctx && ctx->initialized) { - Curl_hash_destroy(&ctx->streams); + Curl_hash_offt_destroy(&ctx->streams); } free(ctx); } @@ -196,8 +197,9 @@ static void h3_stream_ctx_free(struct stream_ctx *stream) free(stream); } -static void h3_stream_hash_free(void *stream) +static void h3_stream_hash_free(curl_off_t id, void *stream) { + (void)id; DEBUGASSERT(stream); h3_stream_ctx_free((struct stream_ctx *)stream); } diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c index 3afdf1a84b..2a90167ac5 100644 --- a/lib/vquic/curl_ngtcp2.c +++ b/lib/vquic/curl_ngtcp2.c @@ -45,7 +45,7 @@ #endif #include "urldata.h" -#include "hash.h" +#include "hash_offt.h" #include "sendf.h" #include "strdup.h" #include "rand.h" @@ -133,7 +133,7 @@ struct cf_ngtcp2_ctx { struct curltime handshake_at; /* time connect handshake finished */ struct bufc_pool stream_bufcp; /* chunk pool for streams */ struct dynbuf scratch; /* temp buffer for header construction */ - struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */ + struct Curl_hash_offt streams; /* hash `data->mid` to `h3_stream_ctx` */ size_t max_stream_window; /* max flow window for one stream */ uint64_t max_idle_ms; /* max idle time for QUIC connection */ uint64_t used_bidi_streams; /* bidi streams we have opened */ @@ -156,7 +156,7 @@ struct cf_ngtcp2_ctx { #define CF_CTX_CALL_DATA(cf) \ ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data -static void h3_stream_hash_free(void *stream); +static void h3_stream_hash_free(curl_off_t id, void *stream); static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx) { @@ -179,8 +179,7 @@ static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx) vquic_ctx_free(&ctx->q); Curl_bufcp_free(&ctx->stream_bufcp); Curl_dyn_free(&ctx->scratch); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); + Curl_hash_offt_destroy(&ctx->streams); Curl_ssl_peer_cleanup(&ctx->peer); } free(ctx); @@ -225,8 +224,9 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream) free(stream); } -static void h3_stream_hash_free(void *stream) +static void h3_stream_hash_free(curl_off_t id, void *stream) { + (void)id; DEBUGASSERT(stream); h3_stream_ctx_free((struct h3_stream_ctx *)stream); } diff --git a/lib/vquic/curl_osslq.c b/lib/vquic/curl_osslq.c index 59cfc4b038..a69da56803 100644 --- a/lib/vquic/curl_osslq.c +++ b/lib/vquic/curl_osslq.c @@ -285,7 +285,7 @@ struct cf_osslq_ctx { struct curltime handshake_at; /* time connect handshake finished */ struct curltime first_byte_at; /* when first byte was recvd */ struct bufc_pool stream_bufcp; /* chunk pool for streams */ - struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */ + struct Curl_hash_offt streams; /* hash `data->mid` to `h3_stream_ctx` */ size_t max_stream_window; /* max flow window for one stream */ uint64_t max_idle_ms; /* max idle time for QUIC connection */ SSL_POLL_ITEM *poll_items; /* Array for polling on writable state */ @@ -299,7 +299,7 @@ struct cf_osslq_ctx { BIT(need_send); /* QUIC connection needs to send */ }; -static void h3_stream_hash_free(void *stream); +static void h3_stream_hash_free(curl_off_t id, void *stream); static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx) { @@ -317,8 +317,7 @@ static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx) { if(ctx && ctx->initialized) { Curl_bufcp_free(&ctx->stream_bufcp); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); + Curl_hash_offt_destroy(&ctx->streams); Curl_ssl_peer_cleanup(&ctx->peer); free(ctx->poll_items); free(ctx->curl_items); @@ -603,8 +602,9 @@ static void h3_stream_ctx_free(struct h3_stream_ctx *stream) free(stream); } -static void h3_stream_hash_free(void *stream) +static void h3_stream_hash_free(curl_off_t id, void *stream) { + (void)id; DEBUGASSERT(stream); h3_stream_ctx_free((struct h3_stream_ctx *)stream); } diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c index 649ddbf98f..0c2bc3309e 100644 --- a/lib/vquic/curl_quiche.c +++ b/lib/vquic/curl_quiche.c @@ -29,7 +29,7 @@ #include #include #include "bufq.h" -#include "hash.h" +#include "hash_offt.h" #include "urldata.h" #include "cfilters.h" #include "cf-socket.h" @@ -97,7 +97,7 @@ struct cf_quiche_ctx { struct curltime started_at; /* time the current attempt started */ struct curltime handshake_at; /* time connect handshake finished */ struct bufc_pool stream_bufcp; /* chunk pool for streams */ - struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */ + struct Curl_hash_offt streams; /* hash `data->mid` to `stream_ctx` */ curl_off_t data_recvd; BIT(initialized); BIT(goaway); /* got GOAWAY from server */ @@ -115,7 +115,7 @@ static void quiche_debug_log(const char *line, void *argp) } #endif -static void h3_stream_hash_free(void *stream); +static void h3_stream_hash_free(curl_off_t id, void *stream); static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx) { @@ -142,8 +142,7 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx) Curl_ssl_peer_cleanup(&ctx->peer); vquic_ctx_free(&ctx->q); Curl_bufcp_free(&ctx->stream_bufcp); - Curl_hash_clean(&ctx->streams); - Curl_hash_destroy(&ctx->streams); + Curl_hash_offt_destroy(&ctx->streams); } free(ctx); } @@ -190,8 +189,9 @@ static void h3_stream_ctx_free(struct stream_ctx *stream) free(stream); } -static void h3_stream_hash_free(void *stream) +static void h3_stream_hash_free(curl_off_t id, void *stream) { + (void)id; DEBUGASSERT(stream); h3_stream_ctx_free((struct stream_ctx *)stream); } diff --git a/tests/unit/unit1616.c b/tests/unit/unit1616.c index 6bccdb9cae..e6608a7938 100644 --- a/tests/unit/unit1616.c +++ b/tests/unit/unit1616.c @@ -25,15 +25,16 @@ #include "curlx.h" -#include "hash.h" +#include "hash_offt.h" #include "memdebug.h" /* LAST include file */ -static struct Curl_hash hash_static; +static struct Curl_hash_offt hash_static; -static void mydtor(void *elem) +static void mydtor(curl_off_t id, void *elem) { int *ptr = (int *)elem; + (void)id; free(ptr); } @@ -45,13 +46,13 @@ static CURLcode unit_setup(void) static void unit_stop(void) { - Curl_hash_destroy(&hash_static); + Curl_hash_offt_destroy(&hash_static); } UNITTEST_START int *value, *v; int *value2; - int *nodep; + bool ok; curl_off_t key = 20; curl_off_t key2 = 25; @@ -60,24 +61,24 @@ UNITTEST_START value = malloc(sizeof(int)); abort_unless(value != NULL, "Out of memory"); *value = 199; - nodep = Curl_hash_offt_set(&hash_static, key, value); - if(!nodep) + ok = Curl_hash_offt_set(&hash_static, key, value); + if(!ok) free(value); - abort_unless(nodep, "insertion into hash failed"); + abort_unless(ok, "insertion into hash failed"); v = Curl_hash_offt_get(&hash_static, key); abort_unless(v == value, "lookup present entry failed"); v = Curl_hash_offt_get(&hash_static, key2); abort_unless(!v, "lookup missing entry failed"); - Curl_hash_clean(&hash_static); + Curl_hash_offt_clear(&hash_static); /* Attempt to add another key/value pair */ value2 = malloc(sizeof(int)); abort_unless(value2 != NULL, "Out of memory"); *value2 = 204; - nodep = Curl_hash_offt_set(&hash_static, key2, value2); - if(!nodep) + ok = Curl_hash_offt_set(&hash_static, key2, value2); + if(!ok) free(value2); - abort_unless(nodep, "insertion into hash failed"); + abort_unless(ok, "insertion into hash failed"); v = Curl_hash_offt_get(&hash_static, key2); abort_unless(v == value2, "lookup present entry failed"); v = Curl_hash_offt_get(&hash_static, key);