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.
This commit is contained in:
Stefan Eissing 2025-02-23 12:20:17 +01:00
parent 049352dd80
commit aeddc0aec9
No known key found for this signature in database
14 changed files with 392 additions and 110 deletions

View File

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

View File

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

View File

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

242
lib/hash_offt.c Normal file
View File

@ -0,0 +1,242 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 <curl/curl.h>
#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 plus memory after it to store the key */
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;
}
}
}
}

67
lib/hash_offt.h Normal file
View File

@ -0,0 +1,67 @@
#ifndef HEADER_CURL_HASH_OFFT_H
#define HEADER_CURL_HASH_OFFT_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, 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 <stddef.h>
#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 */

View File

@ -29,7 +29,7 @@
#include <nghttp2/nghttp2.h>
#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);
}

View File

@ -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;
Curl_hash_offt_visit(&entry->xfers, mev_xfer_expire_cb, (void *)nowp);
/* 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);
}
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);
}

View File

@ -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. */

View File

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

View File

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

View File

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

View File

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

View File

@ -29,7 +29,7 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
#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);
}

View File

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