From 6df10d872b84121b4d0e1fbd7bf91fd8defb3680 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 12 Aug 2022 07:50:43 +0200 Subject: [PATCH] MINOR: ring: support creating a ring from a linear area Instead of allocating two parts, one for the ring struct itself and one for the storage area, ring_make_from_area() will arrange the two inside the same memory area, with the storage starting immediately after the struct. This will allow to store a complete ring state in shared memory areas for example. --- include/haproxy/ring.h | 1 + src/ring.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/include/haproxy/ring.h b/include/haproxy/ring.h index 9e87407c6..bab18c679 100644 --- a/include/haproxy/ring.h +++ b/include/haproxy/ring.h @@ -29,6 +29,7 @@ struct appctx; struct ring *ring_new(size_t size); +struct ring *ring_make_from_area(void *area, size_t size); void ring_init(struct ring *ring, void* area, size_t size); struct ring *ring_resize(struct ring *ring, size_t size); void ring_free(struct ring *ring); diff --git a/src/ring.c b/src/ring.c index c45de29eb..089a2fc9f 100644 --- a/src/ring.c +++ b/src/ring.c @@ -75,6 +75,30 @@ struct ring *ring_new(size_t size) return NULL; } +/* Creates a unified ring + storage area at address for bytes. + * If is null, then it's allocated of the requested size. The ring + * struct is part of the area so the usable area is slightly reduced. However + * the ring storage is immediately adjacent to the struct. ring_free() will + * ignore such rings, so the caller is responsible for releasing them. + */ +struct ring *ring_make_from_area(void *area, size_t size) +{ + struct ring *ring = NULL; + + if (size < sizeof(ring)) + return NULL; + + if (!area) + area = malloc(size); + if (!area) + return NULL; + + ring = area; + area += sizeof(*ring); + ring_init(ring, area, size - sizeof(*ring)); + return ring; +} + /* Resizes existing ring to which must be larger, without losing * its contents. The new size must be at least as large as the previous one or * no change will be performed. The pointer to the ring is returned on success, @@ -113,6 +137,11 @@ void ring_free(struct ring *ring) { if (!ring) return; + + /* make sure it was not allocated by ring_make_from_area */ + if (ring->buf.area == (void *)ring + sizeof(*ring)) + return; + free(ring->buf.area); free(ring); }