aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-22 13:28:36 +0100
committerMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-22 13:28:36 +0100
commit5e8762bec58290701580a68cfdbe73d9836b9fb4 (patch)
tree2948987af762927bcba1eeb102deb12f94d2e94d
parent48f206fa76081a8c8229ba662809175f61710398 (diff)
parentb0a6e504c1d92f27ed90c199d9fc797db489a508 (diff)
downloadlibrb-5e8762bec58290701580a68cfdbe73d9836b9fb4.tar.gz
librb-5e8762bec58290701580a68cfdbe73d9836b9fb4.tar.bz2
librb-5e8762bec58290701580a68cfdbe73d9836b9fb4.zip
add: init rb with custom memory area
This adds possibility to init new rb with custom memory area like it allows to use stack memory instead of dynamic allocation
-rw-r--r--include/rb.h3
-rw-r--r--man/rb_cleanup.31
-rw-r--r--man/rb_clear.33
-rw-r--r--man/rb_destroy.321
-rw-r--r--man/rb_discard.33
-rw-r--r--man/rb_header_size.333
-rw-r--r--man/rb_init.31
-rw-r--r--man/rb_new.369
-rw-r--r--man/rb_overview.715
-rw-r--r--man/rb_read.33
-rw-r--r--man/rb_space.33
-rw-r--r--man/rb_version.33
-rw-r--r--man/rb_write.33
-rw-r--r--rb/rb.c257
-rw-r--r--rb/tests.c72
-rw-r--r--readme.md8
16 files changed, 416 insertions, 82 deletions
diff --git a/include/rb.h b/include/rb.h
index 433fbb0..7a02c0d 100644
--- a/include/rb.h
+++ b/include/rb.h
@@ -25,6 +25,7 @@
struct rb;
struct rb *rb_new(size_t, size_t, unsigned long);
+struct rb *rb_init(size_t, size_t, unsigned long, void *);
long rb_read(struct rb *, void *, size_t);
long rb_recv(struct rb *, void *, size_t, unsigned long);
long rb_write(struct rb *, const void *, size_t);
@@ -32,10 +33,12 @@ long rb_send(struct rb *, const void *, size_t, unsigned long);
int rb_clear(struct rb *, int);
int rb_destroy(struct rb *);
+int rb_cleanup(struct rb *);
int rb_stop(struct rb *);
long rb_discard(struct rb *, size_t);
const char *rb_version(char *, char *, char *);
long rb_count(struct rb *);
long rb_space(struct rb *);
+size_t rb_header_size(void);
#endif
diff --git a/man/rb_cleanup.3 b/man/rb_cleanup.3
new file mode 100644
index 0000000..1888bf1
--- /dev/null
+++ b/man/rb_cleanup.3
@@ -0,0 +1 @@
+.so man3/rb_destroy.3
diff --git a/man/rb_clear.3 b/man/rb_clear.3
index 8fbad09..7dba95a 100644
--- a/man/rb_clear.3
+++ b/man/rb_clear.3
@@ -34,7 +34,9 @@ is invalid (null).
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -43,4 +45,5 @@ is invalid (null).
.BR rb_send (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_destroy.3 b/man/rb_destroy.3
index e88d499..87021ac 100644
--- a/man/rb_destroy.3
+++ b/man/rb_destroy.3
@@ -1,8 +1,9 @@
.TH "rb_destroy" "3" " 9 February 2018 (v1.0.0)" "bofc.pl"
.SH NAME
.PP
-.B rb_destroy,
-.B rb_stop
+.BR rb_stop ,
+.BR rb_destroy ,
+.B rb_cleanup
- functions to stop any locked threads in rb functions and free resources
allocated by
.BR rb_new (3)
@@ -11,6 +12,8 @@ allocated by
.BI "int rb_stop(struct rb *" rb ");"
.br
.BI "int rb_destroy(struct rb *" rb ");"
+.br
+.BI "int rb_cleanup(struct rb *" rb ");"
.SH DESCRIPTION
.PP
Function
@@ -40,13 +43,23 @@ first.
Passing same
.I rb
object twice, will result in segmentation fault.
+.PP
+Function
+.BR rb_cleanup (3)
+works same as
+.BR rb_destroy (3)
+but should be called only on object initialized with
+.BR rb_init (3)
+function.
.SH NOTES
.PP
Due to nature of pthread, you must be sure that no threads are calling
any functions from
.B librb
before calling
-.BR rb_destroy (3).
+.BR rb_destroy (3)
+or
+.BR rb_cleanup (3).
Failing to do so, will lead to deadlocks or crashes sooner or later.
.PP
If you cannot stop threads by yourself before calling
@@ -120,6 +133,7 @@ is invalid (null).
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_read (3),
.BR rb_discard (3),
.BR rb_recv (3),
@@ -128,4 +142,5 @@ is invalid (null).
.BR rb_clear (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_discard.3 b/man/rb_discard.3
index fa5772a..d05daf3 100644
--- a/man/rb_discard.3
+++ b/man/rb_discard.3
@@ -52,7 +52,9 @@ is not a valid object.
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_stop (3),
.BR rb_read (3),
.BR rb_recv (3),
@@ -61,4 +63,5 @@ is not a valid object.
.BR rb_clear (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_header_size.3 b/man/rb_header_size.3
new file mode 100644
index 0000000..0ce4e26
--- /dev/null
+++ b/man/rb_header_size.3
@@ -0,0 +1,33 @@
+.TH "rb_header_size" "3" " 9 February 2018 (v1.0.0)" "bofc.pl"
+.SH NAME
+.PP
+.B rb_header_size
+- read size of
+.B rb
+header in bytes.
+.SH SYNOPSIS
+.PP
+.B "#include <librb.h>"
+.PP
+.B size_t rb_header_size(void);
+.SH RETURN VALUE
+.PP
+Function returns size of iternal struct with information about buffer.
+Size of the buffer with data is not included.
+.SH SEE ALSO
+.PP
+.BR rb_overview (7),
+.BR rb_new (3),
+.BR rb_init (3),
+.BR rb_destroy (3),
+.BR rb_cleanup (3),
+.BR rb_discard (3),
+.BR rb_stop (3),
+.BR rb_read (3),
+.BR rb_recv (3),
+.BR rb_write (3),
+.BR rb_send (3),
+.BR rb_clear (3),
+.BR rb_count (3),
+.BR rb_space (3),
+.BR rb_version (3)
diff --git a/man/rb_init.3 b/man/rb_init.3
new file mode 100644
index 0000000..8012883
--- /dev/null
+++ b/man/rb_init.3
@@ -0,0 +1 @@
+.so man3/rb_new.3
diff --git a/man/rb_new.3 b/man/rb_new.3
index f69c366..1952fe1 100644
--- a/man/rb_new.3
+++ b/man/rb_new.3
@@ -1,14 +1,17 @@
.TH "rb_new" "3" " 9 February 2018 (v1.0.0)" "bofc.pl"
.SH NAME
.PP
-.B rb_new
-- create new ring buffer
+.B rb_new, rb_init
+- initializes new ring buffer
.SH SYNOPSIS
.PP
.BI "#include <librb.h>"
.PP
.BI "struct rb *rb_new(size_t " count ", size_t " object_size ", \
unsigned long " flags ");"
+.br
+.BI "struct rb *rb_init(size_t " count ", size_t " object_size ", \
+unsigned long " flags ", void *" mem ");"
.SH DESCRIPTION
.PP
.BR rb_new (3)
@@ -49,7 +52,26 @@ should be a size of an object, ring buffer will hold.
You should not write nor read objects of different size than created one, as
this will lead to undefined behaviour or even crashes.
.PP
-Function can accept following
+.BR rb_init (3)
+can be used if dynamic allocation is not supported or it needs to be avoided.
+Functions works same as
+.BR rb_new (3)
+but does not perform any allocation and user is responsible to pass pointer to
+.I mem
+that is big enough to hold
+.B rb
+header and any data that could be inserted into buffer.
+Information about header size can be read from
+.BR rb_header_size (3)
+function, and data length can be calculated with formula
+.RI ( count
+*
+.IR object_size ).
+.I mem
+can be whatever continous memory like array on stack, or some custom allocation.
+Check example to see how to use it in practice.
+.PP
+Functions can accept following
.I flags
.TP
.B O_NONBLOCK
@@ -95,10 +117,50 @@ couldn't allocate memory for given
.I count
and
.I object_size
+.SH EXAMPLES
+.PP
+.EX
+.PP
+ #include <rb.h>
+ #include <stdio.h>
+
+ struct msg
+ {
+ int a;
+ int b;
+ };
+
+ int main(void)
+ {
+ struct msg msg;
+ struct rb *rb;
+ /* allocate memory on stack for rb header and 8 elements of msg */
+ unsigned char buf[rb_header_size() + 8 * sizeof(msg)];
+
+ /* initialize ring buffer with custom allocated memory */
+ rb = rb_init(8, sizeof(msg), 0, buf);
+
+ /* rb can be now accessed as usuall */
+
+ /* when work on rb is done, it needs to be cleaned up */
+ rb_cleanup(rb);
+
+ return 0;
+ }
+.EE
+.SH NOTES
+.PP
+Algorithm used in this buffer requires one element to be always empty to
+distinguish situations when buffer is full or empty and as such,
+.B rb
+object can effectively hold
+.I count
+- 1 elements in the buffer.
.SH SEE ALSO
.PP
.BR rb_overview (7),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -108,4 +170,5 @@ and
.BR rb_clear (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_overview.7 b/man/rb_overview.7
index 4dddea7..20f9415 100644
--- a/man/rb_overview.7
+++ b/man/rb_overview.7
@@ -25,11 +25,17 @@ size_t " count ");"
.PP
Additinal functions are provided for better control over buffer
.PP
+.BI "struct rb *rb_init(size_t " count ", size_t " object_size ", \
+unsigned long " flags ", void *" mem ");"
+.br
+.BI "int rb_cleanup(struct rb *" rb ");"
+.br
.BI "long rb_recv(struct rb *" rb ", void *" buffer ", size_t " count ", \
unsigned long " flags ");"
.br
.BI "long rb_send(struct rb *" rb ", const void *" buffer ", \
size_t " count ", unsigned long " flags ");"
+.br
.BI "int rb_clear(struct rb *" rb ", int " clear ");"
.br
.BI "long rb_count(struct rb *" rb ");"
@@ -38,6 +44,8 @@ size_t " count ", unsigned long " flags ");"
.br
.BI "int rb_stop(struct rb *" rb ");"
.br
+.B size_t rb_header_size(void);
+.br
.BI "const char *rb_version(char *" major ", char *" minor ", char *" patch ");"
.SH DESCRIPTION
.PP
@@ -63,6 +71,10 @@ available.
This behaviour can be altered to work in non-blocking mode, so calls from
read and write will return immediately when there are not enough resources.
malloc and free are called only in new and destory functions.
+You can also use buffer and provide own
+.I mem
+pointer to memory that buffer should work on (like so array on stack), in such
+case there will be no dynamic allocations performed by library.
.PP
As this library is focused on speed, user can create buffer with only power of
two count (n^2).
@@ -121,7 +133,9 @@ Please note, that example is missing error handling for simplicity.
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -131,4 +145,5 @@ Please note, that example is missing error handling for simplicity.
.BR rb_clear (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_read.3 b/man/rb_read.3
index f098c20..194e542 100644
--- a/man/rb_read.3
+++ b/man/rb_read.3
@@ -164,7 +164,9 @@ Returned only if threads are enabled.
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -174,4 +176,5 @@ Returned only if threads are enabled.
.BR rb_clear (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_space.3 b/man/rb_space.3
index 8d41990..852cca3 100644
--- a/man/rb_space.3
+++ b/man/rb_space.3
@@ -32,7 +32,9 @@ object is invalid.
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -40,4 +42,5 @@ object is invalid.
.BR rb_write (3),
.BR rb_send (3),
.BR rb_clear (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/man/rb_version.3 b/man/rb_version.3
index 37a7a4a..08213ae 100644
--- a/man/rb_version.3
+++ b/man/rb_version.3
@@ -36,7 +36,9 @@ Function returns pointer to statically allocated string with full version, like
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -45,4 +47,5 @@ Function returns pointer to statically allocated string with full version, like
.BR rb_send (3),
.BR rb_clear (3),
.BR rb_count (3),
+.BR rb_header_size (3),
.BR rb_space (3),
diff --git a/man/rb_write.3 b/man/rb_write.3
index c580315..71315a9 100644
--- a/man/rb_write.3
+++ b/man/rb_write.3
@@ -108,7 +108,9 @@ Returned only if threads are enabled.
.PP
.BR rb_overview (7),
.BR rb_new (3),
+.BR rb_init (3),
.BR rb_destroy (3),
+.BR rb_cleanup (3),
.BR rb_discard (3),
.BR rb_stop (3),
.BR rb_read (3),
@@ -116,4 +118,5 @@ Returned only if threads are enabled.
.BR rb_clear (3),
.BR rb_count (3),
.BR rb_space (3),
+.BR rb_header_size (3),
.BR rb_version (3)
diff --git a/rb/rb.c b/rb/rb.c
index 49d69e2..1d5e314 100644
--- a/rb/rb.c
+++ b/rb/rb.c
@@ -642,6 +642,110 @@ static void *rb_stop_thread
/* ==========================================================================
+ Initializes rb buffer to known state. Does not initialize rb->buffer
+ ========================================================================== */
+
+
+static int rb_init_p
+(
+ struct rb *rb, /* rb object to init */
+ size_t count, /* number of elements that buffer can hold */
+ size_t object_size, /* size, in bytes, of a single object */
+ unsigned long flags /* flags to create buffer with */
+)
+{
+#if ENABLE_THREADS
+ int e; /* errno value from pthread function */
+#endif
+
+ VALID(EINVAL, rb_is_power_of_two(count) == 1);
+
+ rb->head = 0;
+ rb->tail = 0;
+ rb->count = count;
+ rb->object_size = object_size;
+ rb->flags = flags;
+
+#if ENABLE_THREADS == 0
+ /*
+ * multithreaded operations are not allowed when library is compiled
+ * without threads
+ */
+ VALIDR(ENOSYS, NULL, (flags & O_MULTITHREAD) == 0);
+
+ return 0;
+#else
+ if ((flags & O_MULTITHREAD) == 0)
+ {
+ /*
+ * when working in non multi-threaded mode, force O_NONBLOCK flag,
+ * and return, as we don't need to init pthread elements.
+ */
+
+ rb->flags |= O_NONBLOCK;
+ return 0;
+ }
+
+ /*
+ * Multithreaded environment
+ */
+
+ rb->stopped_all = -1;
+ rb->force_exit = 0;
+
+ VALIDGO(e, error_lock, (e = pthread_mutex_init(&rb->lock, NULL)) == 0);
+ VALIDGO(e, error_data, (e = pthread_cond_init(&rb->wait_data, NULL)) == 0);
+ VALIDGO(e, error_room, (e = pthread_cond_init(&rb->wait_room, NULL)) == 0);
+
+ return 0;
+
+error_room:
+ pthread_cond_destroy(&rb->wait_data);
+error_data:
+ pthread_mutex_destroy(&rb->lock);
+error_lock:
+ errno = e;
+ return -1;
+#endif
+}
+
+
+/* ==========================================================================
+ Cleans up resources allocated by pthread stuff
+ ========================================================================== */
+
+
+static int rb_cleanup_p
+(
+ struct rb *rb /* rb object */
+)
+{
+ /*
+ * check if user called rb_stop, if not (rb->stopped will be -1), we trust
+ * caller made sure all threads are stopped before calling destroy.
+ */
+
+ pthread_mutex_lock(&rb->lock);
+ if (rb->stopped_all == 0)
+ {
+ rb->stopped_all = 1;
+ pthread_mutex_unlock(&rb->lock);
+ pthread_join(rb->stop_thread, NULL);
+ }
+ else
+ {
+ pthread_mutex_unlock(&rb->lock);
+ }
+
+ pthread_cond_destroy(&rb->wait_data);
+ pthread_cond_destroy(&rb->wait_room);
+ pthread_mutex_destroy(&rb->lock);
+
+ return 0;
+}
+
+
+/* ==========================================================================
__ __ _
____ __ __ / /_ / /(_)_____
/ __ \ / / / // __ \ / // // ___/
@@ -658,6 +762,38 @@ static void *rb_stop_thread
/* ==========================================================================
+ Initializes new ring buffer object like rb_new but does not use dynamic
+ memory allocation, but uses memory pointer by mem.
+ ========================================================================== */
+
+
+struct rb *rb_init
+(
+ size_t count, /* number of elements that buffer can hold */
+ size_t object_size, /* size, in bytes, of a single object */
+ unsigned long flags, /* flags to create buffer with */
+ void *mem /* memory area to use for rb object */
+)
+{
+ struct rb *rb; /* treat passed mem as rb object */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+ VALIDR(EINVAL, NULL, mem);
+
+ rb = mem;
+ rb->buffer = (unsigned char *)rb + sizeof(*rb);
+
+ if (rb_init_p(rb, count, object_size, flags) == 0)
+ {
+ return rb;
+ }
+
+ return NULL;
+}
+
+
+/* ==========================================================================
Initializes ring buffer and allocates all necessary resources. Newly
created rb will returned as a pointer. In case of an function
error, NULL will be returned
@@ -671,28 +807,10 @@ struct rb *rb_new
unsigned long flags /* flags to create buffer with */
)
{
-#if ENABLE_THREADS
- int e; /* holds errno value */
-#endif
struct rb *rb; /* pointer to newly created buffer */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
-#if ENABLE_THREADS == 0
- /*
- * multithreaded operations are not allowed when library is compiled
- * without threads
- */
-
- VALIDR(ENOSYS, NULL, (flags & O_MULTITHREAD) == 0);
-#endif
-
- if (rb_is_power_of_two(count) == 0)
- {
- errno = EINVAL;
- return NULL;
- }
-
if ((rb = malloc(sizeof(*rb))) == NULL)
{
errno = ENOMEM;
@@ -706,50 +824,14 @@ struct rb *rb_new
return NULL;
}
- rb->head = 0;
- rb->tail = 0;
- rb->count = count;
- rb->object_size = object_size;
- rb->flags = flags;
-
-#if ENABLE_THREADS == 0
- return rb;
-#else
- if ((flags & O_MULTITHREAD) == 0)
+ if (rb_init_p(rb, count, object_size, flags) == 0)
{
- /*
- * when working in non multi-threaded mode, force O_NONBLOCK flag,
- * and return, as we don't need to init pthread elements.
- */
-
- rb->flags |= O_NONBLOCK;
return rb;
}
- /*
- * Multithreaded environment
- */
-
- rb->stopped_all = -1;
- rb->force_exit = 0;
-
- VALIDGO(e, error_lock, (e = pthread_mutex_init(&rb->lock, NULL)) == 0);
- VALIDGO(e, error_data, (e = pthread_cond_init(&rb->wait_data, NULL)) == 0);
- VALIDGO(e, error_room, (e = pthread_cond_init(&rb->wait_room, NULL)) == 0);
-
- return rb;
-
-error_room:
- pthread_cond_destroy(&rb->wait_data);
-error_data:
- pthread_mutex_destroy(&rb->lock);
-error_lock:
- errno = e;
free(rb->buffer);
free(rb);
-
return NULL;
-#endif
}
@@ -939,17 +1021,22 @@ int rb_clear
/* ==========================================================================
Frees resources allocated by rb_new. Due to pthread nature this function
- should be called *only* when no other threads are working on rb object.
+ should be called *only* when no other threads are working on rb object,
+ and rb object was allocated with rb_new.
========================================================================== */
int rb_destroy
(
- struct rb *rb /* rb object */
+ struct rb *rb /* rb object */
)
{
+ int e; /* error code to return */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
VALID(EINVAL, rb);
VALID(EINVAL, rb->buffer);
+ e = 0;
#if ENABLE_THREADS
if ((rb->flags & O_MULTITHREAD) == 0)
@@ -959,30 +1046,36 @@ int rb_destroy
return 0;
}
- /*
- * check if user called rb_stop, if not (rb->stopped will be -1), we trust
- * caller made sure all threads are stopped before calling destroy.
- */
+ e = rb_cleanup_p(rb);
+#endif
- pthread_mutex_lock(&rb->lock);
- if (rb->stopped_all == 0)
- {
- rb->stopped_all = 1;
- pthread_mutex_unlock(&rb->lock);
- pthread_join(rb->stop_thread, NULL);
- }
- else
+ free(rb->buffer);
+ free(rb);
+
+ return e;
+}
+
+
+/* ==========================================================================
+ Same as rb_destroy but should be caled only when rb object was allocated
+ with rb_init function
+ ========================================================================== */
+
+
+int rb_cleanup
+(
+ struct rb *rb /* rb object */
+)
+{
+ VALID(EINVAL, rb);
+
+#if ENABLE_THREADS
+ if (rb->flags & O_MULTITHREAD)
{
- pthread_mutex_unlock(&rb->lock);
+ return rb_cleanup_p(rb);
}
-
- pthread_cond_destroy(&rb->wait_data);
- pthread_cond_destroy(&rb->wait_room);
- pthread_mutex_destroy(&rb->lock);
#endif
- free(rb->buffer);
- free(rb);
return 0;
}
@@ -1177,3 +1270,15 @@ long rb_space
return (long)space;
}
+
+
+/* ==========================================================================
+ Return size of rb struct for current implementation. This size may be
+ different depending on compilation flags and/or architecture
+ ========================================================================== */
+
+
+size_t rb_header_size(void)
+{
+ return sizeof(struct rb);
+}
diff --git a/rb/tests.c b/rb/tests.c
index b0bdd1f..01e6ae7 100644
--- a/rb/tests.c
+++ b/rb/tests.c
@@ -558,16 +558,31 @@ static void count_and_space(void)
static void bad_count_value(void)
{
struct rb *rb;
+ unsigned char rbs[10240];
rb = rb_new(6, 1, 0);
mt_fail(errno == EINVAL);
mt_fail(rb == NULL);
+ rb = rb_init(6, 1, 0, rbs);
+ mt_fail(errno == EINVAL);
+ mt_fail(rb == NULL);
+}
+
+static void enomem(void)
+{
+ struct rb *rb;
+
+ rb = rb_new((size_t)1 << ((sizeof(size_t) * 8) - 1), 1, 0);
+ mt_fail(errno = ENOMEM);
+ mt_fail(rb == NULL);
+ mt_ferr(rb_destroy(rb), EINVAL);
}
static void einval(void)
{
struct rb *rb;
int v;
+ unsigned char rbs[10240];
rb = rb_new(4, 1, 0);
mt_ferr(rb_read(NULL, &v, 1), EINVAL);
@@ -588,7 +603,62 @@ static void einval(void)
mt_ferr(rb_stop(NULL), ENOSYS);
#endif
rb_destroy(rb);
+}
+
+static void stack_init(void)
+{
+ struct msg
+ {
+ int a;
+ int b;
+ } m;
+
+ unsigned char buf[rb_header_size() + 4 * sizeof(m)];
+ struct rb *rb;
+ mt_assert(rb = rb_init(4, sizeof(m), 0, buf));
+ m.a = 1;
+ m.b = 2;
+ rb_write(rb, &m, 1);
+ m.a = 4;
+ m.b = 3;
+ rb_write(rb, &m, 1);
+ m.a = 8;
+ m.b = 7;
+ rb_write(rb, &m, 1);
+ mt_fail(rb_space(rb) == 0);
+ rb_read(rb, &m, 1);
+ mt_fail(m.a == 1);
+ mt_fail(m.b == 2);
+ rb_read(rb, &m, 1);
+ mt_fail(m.a == 4);
+ mt_fail(m.b == 3);
+ rb_read(rb, &m, 1);
+ mt_fail(m.a == 8);
+ mt_fail(m.b == 7);
+ rb_cleanup(rb);
+
+ mt_assert(rb = rb_init(4, sizeof(m), O_MULTITHREAD, buf));
+ m.a = 1;
+ m.b = 2;
+ rb_write(rb, &m, 1);
+ m.a = 4;
+ m.b = 3;
+ rb_write(rb, &m, 1);
+ m.a = 8;
+ m.b = 7;
+ rb_write(rb, &m, 1);
+ mt_fail(rb_space(rb) == 0);
+ rb_read(rb, &m, 1);
+ mt_fail(m.a == 1);
+ mt_fail(m.b == 2);
+ rb_read(rb, &m, 1);
+ mt_fail(m.a == 4);
+ mt_fail(m.b == 3);
+ rb_read(rb, &m, 1);
+ mt_fail(m.a == 8);
+ mt_fail(m.b == 7);
+ rb_cleanup(rb);
}
int main(void)
@@ -644,6 +714,8 @@ int main(void)
mt_run(discard);
mt_run(count_and_space);
mt_run(einval);
+ mt_run(enomem);
+ mt_run(stack_init);
#if ENABLE_THREADS
mt_run(multithread_eagain);
diff --git a/readme.md b/readme.md
index b5ff23c..cb714a2 100644
--- a/readme.md
+++ b/readme.md
@@ -21,6 +21,10 @@ some more functions, it can be operated using 4 basic functions
Additional functions are:
+ * [rb_init](http://librb.kurwinet.pl/manuals/rb_init.3.html) -
+ initializes new ring buffer but does not use dynamic allocation
+ * [rb_cleanup](http://librb.kurwinet.pl/manuals/rb_cleanup.3.html) -
+ cleans up whatever has been initialized with rb_init
* [rb_recv](http://librb.kurwinet.pl/manuals/rb_recv.3.html) -
reads from the ring buffer but also accepts flags
* [rb_send](http://librb.kurwinet.pl/manuals/rb_send.3.html) -
@@ -35,6 +39,10 @@ Additional functions are:
forces all threads to exit **rb_write** and **rb_read** functions
* [rb_discard](http://librb.kurwinet.pl/manuals/rb_discard.3.html) -
allows to quickly discard part of buffers data
+ * [rb_header_size](http://librb.kurwinet.pl/manuals/rb_header_size.3.html) -
+ get size of internal struct with buffer information
+ * [rb_version](http://librb.kurwinet.pl/manuals/rb_version.3.html) -
+ get version of library that is used
Dependencies
============