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