[PATCH] include: Add single-producer single-consumer ringbuffer implementation.

Davide Beatrici winehq at davidebeatrici.dev
Tue Feb 15 00:45:11 CST 2022


I apologize, the patch was not attached to the initial message.

 From: Davide Beatrici <git at davidebeatrici.dev>
Date: Tue, 15 Feb 2022 01:06:13 +0100
Subject: [PATCH] include: Add single-producer single-consumer ringbuffer
  implementation.

The ringbuffer was written for the PipeWire driver I'm working on.

I'm committing it separately because its implementation is generic,
allowing it to be used pretty much universally.

Signed-off-by: Davide Beatrici <git at davidebeatrici.dev>
---
  include/wine/ringbuffer.h | 156 ++++++++++++++++++++++++++++++++++++++
  1 file changed, 156 insertions(+)
  create mode 100644 include/wine/ringbuffer.h

diff --git a/include/wine/ringbuffer.h b/include/wine/ringbuffer.h
new file mode 100644
index 00000000000..50c4651082d
--- /dev/null
+++ b/include/wine/ringbuffer.h
@@ -0,0 +1,156 @@
+/*
+ * Single-producer single-consumer ringbuffer implementation
+ *
+ * Copyright (C) 2022 Davide Beatrici
+ *
+ * this library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * this library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 
02110-1301, USA
+ */
+
+#ifndef __WINE_SERVER_RINGBUFFER_H
+#define __WINE_SERVER_RINGBUFFER_H
+
+#define WIN32_NO_STATUS
+#include "windef.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct ringbuffer
+{
+    BYTE *buf;
+    UINT32 head;
+    UINT32 tail;
+    UINT32 size;
+    volatile UINT32 pending;
+};
+
+static inline struct ringbuffer *ringbuffer_new(const UINT32 size)
+{
+    struct ringbuffer *ringbuffer = malloc(sizeof(*ringbuffer));
+    if (!ringbuffer)
+        return NULL;
+
+    memset(ringbuffer, 0, sizeof(*ringbuffer));
+
+    ringbuffer->buf = malloc(size);
+    if (!ringbuffer->buf) {
+        free(ringbuffer);
+        return NULL;
+    }
+
+    ringbuffer->size = size;
+
+    return ringbuffer;
+}
+
+static inline void ringbuffer_free(struct ringbuffer *ringbuffer)
+{
+    free(ringbuffer->buf);
+    free(ringbuffer);
+}
+
+static inline void ringbuffer_reset(struct ringbuffer *ringbuffer)
+{
+    ringbuffer->head = 0;
+    ringbuffer->tail = 0;
+    ringbuffer->pending = 0;
+}
+
+static inline UINT32 ringbuffer_size(const struct ringbuffer 
*ringbuffer)
+{
+    return ringbuffer->size;
+}
+
+static inline UINT32 ringbuffer_readable(const struct ringbuffer 
*ringbuffer)
+{
+    return ringbuffer->pending;
+}
+
+static inline UINT32 ringbuffer_writable(const struct ringbuffer 
*ringbuffer)
+{
+    return ringbuffer->size - ringbuffer->pending;
+}
+
+static inline UINT32 ringbuffer_read(struct ringbuffer *ringbuffer, 
void *dst, UINT32 size)
+{
+    BYTE *buf = dst;
+    const UINT32 avail = ringbuffer_readable(ringbuffer);
+
+    if (size > avail)
+        size = avail;
+
+    if (!size)
+        return 0;
+
+    if (ringbuffer->head + size <= ringbuffer->size) {
+        memcpy(buf, &ringbuffer->buf[ringbuffer->head], size);
+
+        ringbuffer->head += size;
+    } else {
+        UINT32 size_part = ringbuffer->size - ringbuffer->head;
+
+        memcpy(buf, &ringbuffer->buf[ringbuffer->head], size_part);
+
+        buf += size_part;
+        size_part = size - size_part;
+        memcpy(buf, ringbuffer->buf, size_part);
+
+        ringbuffer->head = size_part;
+    }
+
+    if (ringbuffer->head == ringbuffer->size)
+        ringbuffer->head = 0;
+
+    InterlockedExchangeAdd((volatile LONG *)&ringbuffer->pending, 
-size);
+
+    return size;
+}
+
+static inline UINT32 ringbuffer_write(struct ringbuffer *ringbuffer, 
const void *src, UINT32 size)
+{
+    const BYTE *buf = src;
+    const UINT32 avail = ringbuffer_writable(ringbuffer);
+
+    if (size > avail)
+        size = avail;
+
+    if (!size)
+        return size;
+
+    if (ringbuffer->tail + size <= ringbuffer->size) {
+        memcpy(&ringbuffer->buf[ringbuffer->tail], buf, size);
+
+        ringbuffer->tail += size;
+    } else {
+        UINT32 size_part = ringbuffer->size - ringbuffer->tail;
+
+        memcpy(&ringbuffer->buf[ringbuffer->tail], buf, size_part);
+
+        buf += size_part;
+        size_part = size - size_part;
+        memcpy(ringbuffer->buf, buf, size_part);
+
+        ringbuffer->tail = size_part;
+    }
+
+    if (ringbuffer->tail == ringbuffer->size)
+        ringbuffer->tail = 0;
+
+    InterlockedExchangeAdd((volatile LONG *)&ringbuffer->pending, 
size);
+
+    return size;
+}
+
+#endif  /* __WINE_SERVER_RINGBUFFER_H */
-- 
2.34.1




More information about the wine-devel mailing list