From: William Lallemand Date: Fri, 30 Oct 2026 11:56:50 +0000 (+0100) Subject: MINOR: stream: add per-stream memory slots X-Git-Tag: v3.5-dev11~46 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=d341fd3ee64762486c292609815433063218c218;p=haproxy.git MINOR: stream: add per-stream memory slots Add stream_reserve_memslot() to reserve pointer-aligned per-stream storage during single-threaded initialization, before streams exist. Access the reserved slots with stream_get_memslot(). Reserved storage is zeroed at stream creation, preserved for the stream's lifetime and released on destruction. --- diff --git a/include/haproxy/stream-t.h b/include/haproxy/stream-t.h index 24bc09fae..0d2836e30 100644 --- a/include/haproxy/stream-t.h +++ b/include/haproxy/stream-t.h @@ -359,6 +359,7 @@ struct stream { struct be_counters_shared_tg *sv_tgcounters; /* pointer to current thread group shared server counters */ struct ocsp_clt_check_ctx *ocsp_clt_check_ctx; /* used for client ssl certificate's ocsp check */ + char *memory_slot; /* general-purpose storage accessed via stream_get_memslot() */ }; #endif /* _HAPROXY_STREAM_T_H */ diff --git a/include/haproxy/stream.h b/include/haproxy/stream.h index af5d2f45f..28093a9c6 100644 --- a/include/haproxy/stream.h +++ b/include/haproxy/stream.h @@ -55,6 +55,10 @@ extern struct trace_source trace_strm; #define IS_HTX_STRM(strm) ((strm)->flags & SF_HTX) +extern struct pool_head *pool_head_strm_memslot; +int stream_reserve_memslot(int size); /* Reserve storage during haproxy initialization */ +void *stream_get_memslot(struct stream *s, int offset); /* Access a previously reserved slot */ + extern struct pool_head *pool_head_stream; extern struct pool_head *pool_head_uniqueid; diff --git a/src/stream.c b/src/stream.c index dfa731623..45b2c0946 100644 --- a/src/stream.c +++ b/src/stream.c @@ -62,8 +62,50 @@ #include #include #include +#include +struct pool_head *pool_head_strm_memslot = NULL; + +/* Logical size, independent of pool rounding and debugging overhead. */ +static int stream_memslot_size; + +/* Reserve bytes per stream during initialization, before streams exist. + * Return a pointer-aligned byte offset (possibly zero), or -1 on failure. + */ +int stream_reserve_memslot(int size) +{ + struct pool_head *pool; + unsigned int aligned; + int offset; + + if (size <= 0 || size > INT_MAX - (int)(sizeof(void *) - 1)) + return -1; + aligned = ((unsigned int)size + sizeof(void *) - 1) & ~(sizeof(void *) - 1); + if (aligned > (unsigned int)(INT_MAX - stream_memslot_size)) + return -1; + /* Pools have a fixed block size, so each reservation needs a larger pool. + * Create it first to preserve earlier reservations if allocation fails. + * No streams exist yet, so the previous pool can then be destroyed. + */ + pool = create_pool("strm_memslot", stream_memslot_size + aligned, 0); + if (!pool) + return -1; + pool_destroy(pool_head_strm_memslot); + pool_head_strm_memslot = pool; + offset = stream_memslot_size; + stream_memslot_size += aligned; + return offset; +} + +/* Return the address of the reserved slot at in stream . Requires + * allocated storage and a valid offset returned by stream_reserve_memslot(). + */ +void *stream_get_memslot(struct stream *s, int offset) +{ + return s->memory_slot + offset; +} + DECLARE_TYPED_POOL(pool_head_stream, "stream", struct stream); DECLARE_POOL(pool_head_uniqueid, "uniqueid", UNIQUEID_LEN); @@ -401,6 +443,14 @@ void *stream_new(struct session *sess, struct stconn *sc, struct buffer *input) s->waiting_entity.ptr = NULL; s->stkctr = NULL; + + /* Memory reserved by addons during configuration parsing. */ + s->memory_slot = NULL; + if (pool_head_strm_memslot) { + if (unlikely((s->memory_slot = pool_zalloc(pool_head_strm_memslot)) == NULL)) + goto out_fail_alloc; + } + if (pool_head_stk_ctr) { s->stkctr = pool_alloc(pool_head_stk_ctr); if (!s->stkctr) @@ -610,6 +660,8 @@ void *stream_new(struct session *sess, struct stconn *sc, struct buffer *input) out_fail_alloc: if (s) pool_free(pool_head_stk_ctr, s->stkctr); + if (s) + pool_free(pool_head_strm_memslot, s->memory_slot); pool_free(pool_head_stream, s); DBG_TRACE_DEVEL("leaving on error", STRM_EV_STRM_NEW|STRM_EV_STRM_ERR); return NULL; @@ -792,6 +844,7 @@ void stream_free(struct stream *s) stream_set_target(s, NULL); + pool_free(pool_head_strm_memslot, s->memory_slot); pool_free(pool_head_stream, s); /* We may want to free the maximum amount of pools if the proxy is stopping */ @@ -802,6 +855,7 @@ void stream_free(struct stream *s) pool_flush(pool_head_pcli_txn); pool_flush(pool_head_requri); pool_flush(pool_head_capture); + pool_flush(pool_head_strm_memslot); pool_flush(pool_head_stream); pool_flush(pool_head_session); pool_flush(pool_head_connection);