utils: add helper functions useful for allocating a ring buffer
authorFelix Fietkau <nbd@nbd.name>
Wed, 14 Dec 2016 22:26:51 +0000 (23:26 +0100)
committerFelix Fietkau <nbd@nbd.name>
Wed, 28 Dec 2016 21:44:30 +0000 (22:44 +0100)
This creates a mapping with twice the size of the allocated memory. The
second half of that mapping points at the same memory as the first half.

This is useful for ring buffers, because any read starting in the first
half can overflow into the second half as long as the read size is
smaller than the size of the memory area.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
utils.c
utils.h

diff --git a/utils.c b/utils.c
index 91dd71e6c18dd67dcb5b24a6a93ab88dfa9d887d..e59002ed3062da8a210324d9d1baf9aabb81fdfc 100644 (file)
--- a/utils.c
+++ b/utils.c
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "utils.h"
+#include <sys/mman.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include "utils.h"
 
 #define foreach_arg(_arg, _addr, _len, _first_addr, _first_len) \
        for (_addr = (_first_addr), _len = (_first_len); \
@@ -103,3 +104,48 @@ out:
 }
 
 #endif
+
+void *cbuf_alloc(unsigned int order)
+{
+       char path[] = "/tmp/cbuf-XXXXXX";
+       unsigned long size = cbuf_size(order);
+       void *ret = NULL;
+       int fd;
+
+       fd = mkstemp(path);
+       if (fd < 0)
+               return NULL;
+
+       if (unlink(path))
+               goto close;
+
+       if (ftruncate(fd, cbuf_size(order)))
+               goto close;
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+       ret = mmap(NULL, size * 2, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
+       if (ret == MAP_FAILED) {
+               ret = NULL;
+               goto close;
+       }
+
+       if (mmap(ret, size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
+                fd, 0) != ret ||
+           mmap(ret + size, size, PROT_READ | PROT_WRITE,
+                MAP_FIXED | MAP_SHARED, fd, 0) != ret + size) {
+               munmap(ret, size * 2);
+               ret = NULL;
+       }
+
+close:
+       close(fd);
+       return ret;
+}
+
+void cbuf_free(void *ptr, unsigned int order)
+{
+       munmap(ptr, cbuf_size(order) * 2);
+}
diff --git a/utils.h b/utils.h
index d00e76b2f0dc89f5ddc401bb3b404617a0fd96e6..803150bfa475b51ad8e7edef5649383e4eb04b0f 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -23,6 +23,7 @@
 #include <sys/time.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <unistd.h>
 #include <time.h>
 
 /*
@@ -192,4 +193,23 @@ int b64_decode(const void *src, void *dest, size_t dest_len);
 #define B64_ENCODE_LEN(_len)   ((((_len) + 2) / 3) * 4 + 1)
 #define B64_DECODE_LEN(_len)   (((_len) / 4) * 3 + 1)
 
+static inline unsigned int cbuf_order(unsigned int x)
+{
+       return 32 - __builtin_clz(x - 1);
+}
+
+static inline unsigned long cbuf_size(int order)
+{
+       unsigned long page_size = sysconf(_SC_PAGESIZE);
+       unsigned long ret = 1ULL << order;
+
+       if (ret < page_size)
+               ret = page_size;
+
+       return ret;
+}
+
+void *cbuf_alloc(unsigned int order);
+void cbuf_free(void *ptr, unsigned int order);
+
 #endif