aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHanspeter Portner <dev@open-music-kontrollers.ch>2015-05-20 15:26:53 +0200
committerHanspeter Portner <dev@open-music-kontrollers.ch>2015-05-20 15:26:53 +0200
commit1334b77d6c7f492f02a9b6b92f8024457635f384 (patch)
tree759227f72de9353011026980fda1d6f1951ec3d0
parent06057c359779b4b415f346afcb44fdee37b98d48 (diff)
downloadvarchunk-1334b77d6c7f492f02a9b6b92f8024457635f384.tar.xz
convert to single header file.
-rw-r--r--.travis.yml4
-rw-r--r--CMakeLists.txt13
-rw-r--r--varchunk.c280
-rw-r--r--varchunk.h286
4 files changed, 289 insertions, 294 deletions
diff --git a/.travis.yml b/.travis.yml
index 034ff08..d9d8ba1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,6 +9,6 @@ before_install:
install:
- pushd libuv-1.4.2 && sh autogen.sh && ./configure --prefix=/usr && make && sudo make install && popd
before_script:
- - mkdir build && pushd build && cmake .. && popd
+ - mkdir build && pushd build && cmake -DBUILD_TESTING=1 -DCMAKE_BUILD_TYPE=Debug.. && popd
script:
- - pushd build && make && ./test_varchunk && popd
+ - pushd build && make && ARGS="-VV" make test && popd
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1282687..825888b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,8 +11,11 @@ find_package(PkgConfig REQUIRED)
pkg_search_module(UV REQUIRED libuv>=1.0)
include_directories(${UV_INCLUDE_DIRS})
-# varchunk test
-add_executable(test_varchunk
- test_varchunk.c
- varchunk.c)
-target_link_libraries(test_varchunk ${UV_LDFLAGS})
+include(CTest)
+if(${BUILD_TESTING})
+ add_executable(test_varchunk
+ test_varchunk.c)
+ target_link_libraries(test_varchunk ${UV_LDFLAGS})
+
+ add_test(API-Test test_varchunk)
+endif()
diff --git a/varchunk.c b/varchunk.c
deleted file mode 100644
index 1e9e7fd..0000000
--- a/varchunk.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 2015 Hanspeter Portner (dev@open-music-kontrollers.ch)
- *
- * This is free software: you can redistribute it and/or modify
- * it under the terms of the Artistic License 2.0 as published by
- * The Perl Foundation.
- *
- * This source 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
- * Artistic License 2.0 for more details.
- *
- * You should have received a copy of the Artistic License 2.0
- * along the source as a COPYING file. If not, obtain it from
- * http://www.perlfoundation.org/artistic_license_2_0.
- */
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <assert.h>
-
-#if !defined(_WIN32)
-# include <sys/mman.h> // mlock
-#endif
-
-#include <varchunk.h>
-
-#define VARCHUNK_PAD(SIZE) ( ( (size_t)(SIZE) + 7U ) & ( ~7U ) )
-
-typedef struct _varchunk_elmnt_t varchunk_elmnt_t;
-
-struct _varchunk_elmnt_t {
- uint32_t size;
- uint32_t gap;
-};
-
-struct _varchunk_t {
- size_t size;
- size_t mask;
- size_t rsvd;
-
- volatile size_t head;
- volatile size_t tail;
-
- void *buf;
-};
-
-varchunk_t *
-varchunk_new(size_t minimum)
-{
- varchunk_t *varchunk;
-
- if(!(varchunk = calloc(1, sizeof(varchunk_t))))
- return NULL;
-
- varchunk->size = 1;
- while(varchunk->size < minimum)
- varchunk->size <<= 1;
- varchunk->mask = varchunk->size - 1;
-
-#if defined(_WIN32)
- varchunk->buf = _aligned_malloc(varchunk->size, sizeof(varchunk_elmnt_t));
-#else
- posix_memalign(&varchunk->buf, sizeof(varchunk_elmnt_t), varchunk->size);
- mlock(varchunk->buf, varchunk->size);
-#endif
- if(!varchunk->buf)
- {
- free(varchunk);
- return NULL;
- }
- //TODO mlock
-
- return varchunk;
-}
-
-void
-varchunk_free(varchunk_t *varchunk)
-{
- if(varchunk)
- {
- if(varchunk->buf)
- {
-#if !defined(_WIN32)
- munlock(varchunk->buf, varchunk->size);
-#endif
- free(varchunk->buf);
- }
- free(varchunk);
- }
-}
-
-static inline void
-_varchunk_write_advance_raw(varchunk_t *varchunk, size_t written)
-{
- // only producer is allowed to advance write head
- size_t new_head = (varchunk->head + written) & varchunk->mask;
- varchunk->head = new_head;
-}
-
-void *
-varchunk_write_request(varchunk_t *varchunk, size_t minimum)
-{
- if(minimum == 0)
- {
- varchunk->rsvd = 0;
- return NULL;
- }
-
- size_t space; // size of writable buffer
- size_t end; // virtual end of writable buffer
- size_t head = varchunk->head; // read head
- size_t tail = varchunk->tail; // read tail ONCE (consumer modifies it any time)
- size_t padded = 2*sizeof(varchunk_elmnt_t) + VARCHUNK_PAD(minimum);
-
- // calculate writable space
- if(head > tail)
- space = ((tail - head + varchunk->size) & varchunk->mask) - 1;
- else if(head < tail)
- space = (tail - head) - 1;
- else // head == tail
- space = varchunk->size - 1;
- end = head + space;
-
- if(end > varchunk->size) // available region wraps over at end of buffer
- {
- // get first part of available buffer
- void *buf1 = varchunk->buf + head;
- size_t len1 = varchunk->size - head;
-
- if(len1 < padded) // not enough space left on first part of buffer
- {
- // get second part of available buffer
- void *buf2 = varchunk->buf;
- size_t len2 = end & varchunk->mask;
-
- if(len2 < padded) // not enough space left on second buffer, either
- {
- varchunk->rsvd = 0;
- return NULL;
- }
- else // enough space left on second buffer, use it!
- {
- // fill end of first buffer with gap
- varchunk_elmnt_t *elmnt = buf1;
- elmnt->size = len1 - sizeof(varchunk_elmnt_t);
- elmnt->gap = 1;
- _varchunk_write_advance_raw(varchunk, len1);
-
- varchunk->rsvd = minimum;
- return buf2 + sizeof(varchunk_elmnt_t);
- }
- }
- else // enough space left on first part of buffer, use it!
- {
- varchunk->rsvd = minimum;
- return buf1 + sizeof(varchunk_elmnt_t);
- }
- }
- else // available region is contiguous
- {
- void *buf = varchunk->buf + head;
-
- if(space < padded) // no space left on contiguous buffer
- {
- varchunk->rsvd = 0;
- return NULL;
- }
- else // enough space on contiguous buffer, use it!
- {
- varchunk->rsvd = minimum;
- return buf + sizeof(varchunk_elmnt_t);
- }
- }
-}
-
-void
-varchunk_write_advance(varchunk_t *varchunk, size_t written)
-{
- // fail miserably if stupid programmer tries to write more than rsvd
- assert(written <= varchunk->rsvd);
-
- // write elmnt header at head
- varchunk_elmnt_t *elmnt = varchunk->buf + varchunk->head;
- elmnt->size = written;
- elmnt->gap = 0;
-
- // advance write head
- _varchunk_write_advance_raw(varchunk,
- sizeof(varchunk_elmnt_t) + VARCHUNK_PAD(written));
-}
-
-static inline void
-_varchunk_read_advance_raw(varchunk_t *varchunk, size_t read)
-{
- // only consumer is allowed to advance read tail
- size_t new_tail = (varchunk->tail + read) & varchunk->mask;
- varchunk->tail = new_tail;
-}
-
-const void *
-varchunk_read_request(varchunk_t *varchunk, size_t *toread)
-{
- size_t space; // size of available buffer
- size_t head = varchunk->head; // read head ONCE (producer modifies it any time)
- size_t tail = varchunk->tail; // read tail
-
- // calculate readable space
- if(head > tail)
- space = head - tail;
- else
- space = (head - tail + varchunk->size) & varchunk->mask;
-
- if(space > 0) // there may be chunks available for reading
- {
- size_t end = tail + space; // virtual end of available buffer
-
- if(end > varchunk->size) // available buffer wraps around at end
- {
- // first part of available buffer
- void *buf1 = varchunk->buf + tail;
- size_t len1 = varchunk->size - tail;
- const varchunk_elmnt_t *elmnt = buf1;
-
- if(elmnt->gap) // gap elmnt?
- {
- // skip gap
- _varchunk_read_advance_raw(varchunk, len1);
-
- // second part of available buffer
- void *buf2 = varchunk->buf;
- elmnt = buf2;
-
- *toread = elmnt->size;
- return buf2 + sizeof(varchunk_elmnt_t);
- }
- else // valid chunk, use it!
- {
- *toread = elmnt->size;
- return buf1 + sizeof(varchunk_elmnt_t);
- }
- }
- else // available buffer is contiguous
- {
- // get buffer
- void *buf = varchunk->buf + tail;
- const varchunk_elmnt_t *elmnt = buf;
-
- if(elmnt->gap) // a single gap elmnt?
- {
- // skip gap
- _varchunk_read_advance_raw(varchunk, space);
-
- *toread = 0;
- return NULL;
- }
- else // valid chunk, use it!
- {
- *toread = elmnt->size;
- return buf + sizeof(varchunk_elmnt_t);
- }
- }
- }
- else // no chunks available aka empty buffer
- {
- *toread = 0;
- return NULL;
- }
-}
-
-void
-varchunk_read_advance(varchunk_t *varchunk)
-{
- // get elmnt header from tail (for size)
- const varchunk_elmnt_t *elmnt = varchunk->buf + varchunk->tail;
-
- // advance read tail
- _varchunk_read_advance_raw(varchunk,
- sizeof(varchunk_elmnt_t) + VARCHUNK_PAD(elmnt->size));
-}
diff --git a/varchunk.h b/varchunk.h
index 056de44..0178af1 100644
--- a/varchunk.h
+++ b/varchunk.h
@@ -22,28 +22,300 @@
extern "C" {
#endif
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#if !defined(_WIN32)
+# include <sys/mman.h> // mlock
+#endif
+
+/*****************************************************************************
+ * API START
+ *****************************************************************************/
+
typedef struct _varchunk_t varchunk_t;
-varchunk_t *
+static inline varchunk_t *
varchunk_new(size_t minimum);
-void
+static inline void
varchunk_free(varchunk_t *varchunk);
-void *
+static inline void *
varchunk_write_request(varchunk_t *varchunk, size_t minimum);
-void
+static inline void
varchunk_write_advance(varchunk_t *varchunk, size_t written);
-const void *
+static inline const void *
varchunk_read_request(varchunk_t *varchunk, size_t *toread);
-void
+static inline void
varchunk_read_advance(varchunk_t *varchunk);
+/*****************************************************************************
+ * API END
+ *****************************************************************************/
+
+#define VARCHUNK_PAD(SIZE) ( ( (size_t)(SIZE) + 7U ) & ( ~7U ) )
+
+typedef struct _varchunk_elmnt_t varchunk_elmnt_t;
+
+struct _varchunk_elmnt_t {
+ uint32_t size;
+ uint32_t gap;
+};
+
+struct _varchunk_t {
+ size_t size;
+ size_t mask;
+ size_t rsvd;
+
+ volatile size_t head;
+ volatile size_t tail;
+
+ void *buf;
+};
+
+static inline varchunk_t *
+varchunk_new(size_t minimum)
+{
+ varchunk_t *varchunk;
+
+ if(!(varchunk = calloc(1, sizeof(varchunk_t))))
+ return NULL;
+
+ varchunk->size = 1;
+ while(varchunk->size < minimum)
+ varchunk->size <<= 1;
+ varchunk->mask = varchunk->size - 1;
+
+#if defined(_WIN32)
+ varchunk->buf = _aligned_malloc(varchunk->size, sizeof(varchunk_elmnt_t));
+#else
+ posix_memalign(&varchunk->buf, sizeof(varchunk_elmnt_t), varchunk->size);
+ mlock(varchunk->buf, varchunk->size);
+#endif
+ if(!varchunk->buf)
+ {
+ free(varchunk);
+ return NULL;
+ }
+ //TODO mlock
+
+ return varchunk;
+}
+
+static inline void
+varchunk_free(varchunk_t *varchunk)
+{
+ if(varchunk)
+ {
+ if(varchunk->buf)
+ {
+#if !defined(_WIN32)
+ munlock(varchunk->buf, varchunk->size);
+#endif
+ free(varchunk->buf);
+ }
+ free(varchunk);
+ }
+}
+
+static inline void
+_varchunk_write_advance_raw(varchunk_t *varchunk, size_t written)
+{
+ // only producer is allowed to advance write head
+ size_t new_head = (varchunk->head + written) & varchunk->mask;
+ varchunk->head = new_head;
+}
+
+static inline void *
+varchunk_write_request(varchunk_t *varchunk, size_t minimum)
+{
+ if(minimum == 0)
+ {
+ varchunk->rsvd = 0;
+ return NULL;
+ }
+
+ size_t space; // size of writable buffer
+ size_t end; // virtual end of writable buffer
+ size_t head = varchunk->head; // read head
+ size_t tail = varchunk->tail; // read tail ONCE (consumer modifies it any time)
+ size_t padded = 2*sizeof(varchunk_elmnt_t) + VARCHUNK_PAD(minimum);
+
+ // calculate writable space
+ if(head > tail)
+ space = ((tail - head + varchunk->size) & varchunk->mask) - 1;
+ else if(head < tail)
+ space = (tail - head) - 1;
+ else // head == tail
+ space = varchunk->size - 1;
+ end = head + space;
+
+ if(end > varchunk->size) // available region wraps over at end of buffer
+ {
+ // get first part of available buffer
+ void *buf1 = varchunk->buf + head;
+ size_t len1 = varchunk->size - head;
+
+ if(len1 < padded) // not enough space left on first part of buffer
+ {
+ // get second part of available buffer
+ void *buf2 = varchunk->buf;
+ size_t len2 = end & varchunk->mask;
+
+ if(len2 < padded) // not enough space left on second buffer, either
+ {
+ varchunk->rsvd = 0;
+ return NULL;
+ }
+ else // enough space left on second buffer, use it!
+ {
+ // fill end of first buffer with gap
+ varchunk_elmnt_t *elmnt = buf1;
+ elmnt->size = len1 - sizeof(varchunk_elmnt_t);
+ elmnt->gap = 1;
+ _varchunk_write_advance_raw(varchunk, len1);
+
+ varchunk->rsvd = minimum;
+ return buf2 + sizeof(varchunk_elmnt_t);
+ }
+ }
+ else // enough space left on first part of buffer, use it!
+ {
+ varchunk->rsvd = minimum;
+ return buf1 + sizeof(varchunk_elmnt_t);
+ }
+ }
+ else // available region is contiguous
+ {
+ void *buf = varchunk->buf + head;
+
+ if(space < padded) // no space left on contiguous buffer
+ {
+ varchunk->rsvd = 0;
+ return NULL;
+ }
+ else // enough space on contiguous buffer, use it!
+ {
+ varchunk->rsvd = minimum;
+ return buf + sizeof(varchunk_elmnt_t);
+ }
+ }
+}
+
+static inline void
+varchunk_write_advance(varchunk_t *varchunk, size_t written)
+{
+ // fail miserably if stupid programmer tries to write more than rsvd
+ assert(written <= varchunk->rsvd);
+
+ // write elmnt header at head
+ varchunk_elmnt_t *elmnt = varchunk->buf + varchunk->head;
+ elmnt->size = written;
+ elmnt->gap = 0;
+
+ // advance write head
+ _varchunk_write_advance_raw(varchunk,
+ sizeof(varchunk_elmnt_t) + VARCHUNK_PAD(written));
+}
+
+static inline void
+_varchunk_read_advance_raw(varchunk_t *varchunk, size_t read)
+{
+ // only consumer is allowed to advance read tail
+ size_t new_tail = (varchunk->tail + read) & varchunk->mask;
+ varchunk->tail = new_tail;
+}
+
+static inline const void *
+varchunk_read_request(varchunk_t *varchunk, size_t *toread)
+{
+ size_t space; // size of available buffer
+ size_t head = varchunk->head; // read head ONCE (producer modifies it any time)
+ size_t tail = varchunk->tail; // read tail
+
+ // calculate readable space
+ if(head > tail)
+ space = head - tail;
+ else
+ space = (head - tail + varchunk->size) & varchunk->mask;
+
+ if(space > 0) // there may be chunks available for reading
+ {
+ size_t end = tail + space; // virtual end of available buffer
+
+ if(end > varchunk->size) // available buffer wraps around at end
+ {
+ // first part of available buffer
+ void *buf1 = varchunk->buf + tail;
+ size_t len1 = varchunk->size - tail;
+ const varchunk_elmnt_t *elmnt = buf1;
+
+ if(elmnt->gap) // gap elmnt?
+ {
+ // skip gap
+ _varchunk_read_advance_raw(varchunk, len1);
+
+ // second part of available buffer
+ void *buf2 = varchunk->buf;
+ elmnt = buf2;
+
+ *toread = elmnt->size;
+ return buf2 + sizeof(varchunk_elmnt_t);
+ }
+ else // valid chunk, use it!
+ {
+ *toread = elmnt->size;
+ return buf1 + sizeof(varchunk_elmnt_t);
+ }
+ }
+ else // available buffer is contiguous
+ {
+ // get buffer
+ void *buf = varchunk->buf + tail;
+ const varchunk_elmnt_t *elmnt = buf;
+
+ if(elmnt->gap) // a single gap elmnt?
+ {
+ // skip gap
+ _varchunk_read_advance_raw(varchunk, space);
+
+ *toread = 0;
+ return NULL;
+ }
+ else // valid chunk, use it!
+ {
+ *toread = elmnt->size;
+ return buf + sizeof(varchunk_elmnt_t);
+ }
+ }
+ }
+ else // no chunks available aka empty buffer
+ {
+ *toread = 0;
+ return NULL;
+ }
+}
+
+static inline void
+varchunk_read_advance(varchunk_t *varchunk)
+{
+ // get elmnt header from tail (for size)
+ const varchunk_elmnt_t *elmnt = varchunk->buf + varchunk->tail;
+
+ // advance read tail
+ _varchunk_read_advance_raw(varchunk,
+ sizeof(varchunk_elmnt_t) + VARCHUNK_PAD(elmnt->size));
+}
+
+#undef VARCHUNK_PAD
+
#ifdef __cplusplus
}
#endif
-#endif //_VARCHUNK_CHUNK_H
+#endif //_VARCHUNK_H