aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-01 08:14:14 +0100
committerMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-01 08:14:14 +0100
commit6a7e8cf9a3cefb162a2c78b2f22c004693081acd (patch)
tree122bf7e177ce91e051ea6e139f28a0aa972b0e95
parent37cc2ad02f5e7e75f5eec5b3fd23500b89879c58 (diff)
parente66d7bac550bbf3be263132a1fa4dfd568ab885f (diff)
downloadlibrb-6a7e8cf9a3cefb162a2c78b2f22c004693081acd.tar.gz
librb-6a7e8cf9a3cefb162a2c78b2f22c004693081acd.tar.bz2
librb-6a7e8cf9a3cefb162a2c78b2f22c004693081acd.zip
Change: make rb_new() to create non-thread object by default
Remove O_NONBLOCK flag and create new O_MULTITHREAD. Previous solution did not allow to check if rb is multi or single threaded, and rb object creation was not too standard - it could create multi or single threaded object depending on how library was compiled. This patch standarizes behaviour. Unfurtunately it also breaks API.
-rw-r--r--include/rb.h2
-rw-r--r--man/rb_new.350
-rw-r--r--man/rb_overview.732
-rw-r--r--rb/rb.c47
-rw-r--r--rb/tests.c62
5 files changed, 108 insertions, 85 deletions
diff --git a/include/rb.h b/include/rb.h
index 574a4d3..4e00305 100644
--- a/include/rb.h
+++ b/include/rb.h
@@ -21,7 +21,7 @@
#define MSG_DONTWAIT 0x40
#endif
-#define O_NONTHREAD 0x00010000L
+#define O_MULTITHREAD 0x00010000L
struct rb;
typedef long (*rb_send_f)(struct rb *, const void *, size_t , unsigned long);
diff --git a/man/rb_new.3 b/man/rb_new.3
index 19c5c04..2dc945d 100644
--- a/man/rb_new.3
+++ b/man/rb_new.3
@@ -59,43 +59,21 @@ Proper functions will then return with errno set to
.B EAGAIN
and number of elements actually commited.
This is default behaviour when
+.B O_MULTITHREAD
+flag was
+.B not
+passed and
.B librb
-is compiler without
-.BR ENABLE_THREADS.
+is working in single thread mode.
.TP
-.B O_NONTHREAD
+.B O_MULTITHREAD
this can be set only when library has been compiled with
-.B ENABLE_THREADS
-otherwise, this flag is ignored. If set,
+.BR ENABLE_THREADS ,
+otherwise error will be returned. If set,
.B librb
-functions will not be using pthread.
-This should be used only when you are sure that
+functions will be using pthreads to provide synchronization of threads accessing
.I rb
-object will be accessed at most by 1 thread at a time.
-If more than 1 thread will try access
-.I rb
-object when this flag is set, such call will result in undefined behaviour.
-When
-.B O_NONTHREAD
-is set,
-.B O_NONBLOCK
-should also be set so
-all function calls are non-blocking.
-If
-.B ENABLE_THREADS
-is not set, funcions
-behave as (
-.B O_NONTHREAD
-|
-.BR O_NONBLOCK )
-flag was set.
-When this flag is passed to
-.BR rb_new (3),
-user should also set
-.B O_NONBLOCK
-or
-.B EINVAL
-error will be returned to prevent deadlocks.
+object.
.SH RETURN VALUES
.PP
If no errors have been detected, function will return pointer to newly created
@@ -106,11 +84,11 @@ ring buffer, otherwise NULL is returned.
.I count
is not a power of two number (like 4, 64, 1024).
.TP
-.B EINVAL
-.B O_NONTHREAD
+.B ENOSYS
+.B O_MULTITHREAD
was set but
-.B O_NONBLOCK
-was not (only when library was compiled with pthread support.
+.B librb
+was not compiled with pthread support.
.TP
.B ENOMEM
couldn't allocate memory for given
diff --git a/man/rb_overview.7 b/man/rb_overview.7
index 2d8f6fc..2469616 100644
--- a/man/rb_overview.7
+++ b/man/rb_overview.7
@@ -42,19 +42,27 @@ size_t " count ", unsigned long " flags ");"
.SH DESCRIPTION
.PP
.B librb
-is thread safe and thread aware.
-If there are no resources available while reading or writting, caller thread
-gets locked and doesn't use any resources until data is available.
-Ring buffer can also be configured to work in non-blocking mode, so calls from
+is a simple ring buffer implementation that operates on objects rather than
+raw bytes.
+See
+.BR rb_new (3)
+to know what that means.
+By default library operates in single-thread mode which is way faster than
+multi-thread mode but naturally will break if concurrent thread will try to
+access
+.I rb
+object.
+To relief user from pesky synchronization process, library can optionally be
+thread safe and thread aware by passing
+.B O_MULTITHREAD
+flag to
+.BR rb_new (3).
+In multi-thread mode if there are no resources available while reading or
+writting, caller thread gets locked and doesn't use any resources until data is
+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.
-Thread awarness can be disabled via
-.B O_NONTHREAD
-flags passed to
-.BR rb_new (3).
-In such case all calls to rb function will be non blocking.
-Library can also be compiled without thread support at all, then it can be used
-even in very constrained platforms.
.PP
As this library is focused on speed, user can create buffer with only power of
two count (n^2).
@@ -80,7 +88,7 @@ Please note, that example is missing error handling for simplicity.
struct rb *rb;
/* initialize ring buffer with 32 1-byte elements */
- rb = rb_new(32, 1, O_NONBLOCK | O_NONTHREAD);
+ rb = rb_new(32, 1, 0);
/* add data to buffer one byte at a time */
for (i = '0'; i <= '9'; ++i)
diff --git a/rb/rb.c b/rb/rb.c
index f6e40e9..c885fe8 100644
--- a/rb/rb.c
+++ b/rb/rb.c
@@ -424,7 +424,6 @@ static long rb_sends
#if ENABLE_THREADS
-#include <stdio.h>
long rb_sendt
(
@@ -608,6 +607,14 @@ struct rb *rb_new
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)
{
@@ -637,9 +644,14 @@ struct rb *rb_new
#if ENABLE_THREADS == 0
return rb;
#else
- if (flags & O_NONTHREAD)
+ if ((flags & O_MULTITHREAD) == 0)
{
- VALIDGO(EINVAL, error, flags & O_NONBLOCK)
+ /*
+ * when working in non multi-threaded mode, force O_NONBLOCK flag,
+ * and return, as we don't need to init pthread elements.
+ */
+
+ flags |= O_NONBLOCK;
return rb;
}
@@ -674,10 +686,10 @@ error:
/* ==========================================================================
Reads maximum of count elements from rb and stores them into buffer.
- If rb is O_NONTHREAD or O_NONBLOCK, function will never block, and
- cannot guarantee writing count elements into buffer. If there is not
- enough data in ring buffer, function will read whole buffer and
- return with elements read.
+ If rb is working in single thread mode or O_NONBLOCK flag is set,
+ function will never block, and cannot guarantee writing count elements
+ into buffer. If there is not enough data in ring buffer, function will
+ read whole buffer and return with elements read.
If rb is threaded and blocking, function will block (sleep) caller
thread until all count elements were copied into buffer. Function
@@ -714,7 +726,7 @@ long rb_recv
VALID(EINVAL, rb->buffer);
#if ENABLE_THREADS
- if (rb->flags & O_NONTHREAD)
+ if ((rb->flags & O_MULTITHREAD) == 0)
{
return rb_recvs(rb, buffer, count, flags);
}
@@ -752,13 +764,14 @@ long rb_recv
/* ==========================================================================
Writes maximum count data from buffer into rb.
- If rb is O_NONTHREAD or O_NONBLOCK, function will never block, but also
- cannot guarantee that count elements will be copied from buffer. If
- there is not enough space in rb, function will store as many elements as
- it can, and return with number of elements stored into rb.
+ If rb is working in single thread mode or O_NONBLOCK flag is set,
+ function will never block, but also cannot guarantee that count elements
+ will be copied from buffer. If there is not enough space in rb, function
+ will store as many elements as it can, and return with number of
+ elements stored into rb.
- If rb is multithreaded, and blocking function will block (sleep) caller
- until count elements have been stored into rb.
+ If rb is multithreaded, and in blocking mode function will block (sleep)
+ caller until count elements have been stored into rb.
Function os equivalent to call rb_send with flags == 0
========================================================================== */
@@ -793,7 +806,7 @@ long rb_send
VALID(EINVAL, rb->buffer);
#if ENABLE_THREADS
- if (rb->flags & O_NONTHREAD)
+ if ((rb->flags & O_MULTITHREAD) == 0)
{
return rb_sends(rb, buffer, count, flags);
}
@@ -869,7 +882,7 @@ int rb_destroy
VALID(EINVAL, rb->buffer);
#if ENABLE_THREADS
- if (rb->flags & O_NONTHREAD)
+ if ((rb->flags & O_MULTITHREAD) == 0)
{
free(rb->buffer);
free(rb);
@@ -921,7 +934,7 @@ int rb_stop
VALID(EINVAL, rb);
- VALID(EINVAL, (rb->flags & O_NONTHREAD) != O_NONTHREAD);
+ VALID(EINVAL, rb->flags & O_MULTITHREAD);
rb->stopped_all = 0;
if ((e = pthread_create(&rb->stop_thread, NULL, rb_stop_thread, rb)) != 0)
diff --git a/rb/tests.c b/rb/tests.c
index a388514..f7537b6 100644
--- a/rb/tests.c
+++ b/rb/tests.c
@@ -141,7 +141,7 @@ static void multi_producers_consumers(void)
cons = malloc(t_num_consumers * sizeof(*cons));
prod = malloc(t_num_producers * sizeof(*prod));
- rb = rb_new(8, sizeof(unsigned int), 0);
+ rb = rb_new(8, sizeof(unsigned int), O_MULTITHREAD);
pthread_mutex_init(&multi_mutex, NULL);
pthread_mutex_init(&multi_mutex_count, NULL);
@@ -230,7 +230,7 @@ static void multi_thread(void)
recv_buf[i] = 0;
}
- rb = rb_new(t_rblen, t_objsize, 0);
+ rb = rb_new(t_rblen, t_objsize, O_MULTITHREAD);
proddata.data = send_buf;
proddata.len = t_writelen;
@@ -265,18 +265,51 @@ static void multi_thread(void)
}
-static void nonthread_without_nonblock(void)
+#endif
+
+static void multithread_flag(void)
{
struct rb *rb;
- rb = rb_new(4, 1, O_NONTHREAD);
- mt_fail(errno == EINVAL);
- mt_fail(rb == NULL);
+ rb = rb_new(4, 1, O_MULTITHREAD);
+
+#if ENABLE_THREADS
+ mt_assert(rb != NULL);
rb_destroy(rb);
+#else
+ mt_assert(rb == NULL);
+ mt_assert(errno == ENOSYS);
+#endif
}
+static void nonblocking_flag(void)
+{
+ struct rb *rb;
+ char s[6] = {0, 1, 2, 3, 4, 5};
+ char e[3] = {0, 1, 2};
+ char d[6];
+ int r;
+
+#if ENABLE_THREADS
+ rb = rb_new(4, 1, O_NONBLOCK | O_MULTITHREAD);
+ r = rb_write(rb, s, sizeof(s));
+ mt_fail(r == 3);
+ r = rb_read(rb, d, sizeof(d));
+ mt_fail(r == 3);
+ mt_fok(memcmp(d, e, sizeof(e)));
+ rb_destroy(rb);
+ memset(d, 0, sizeof(d));
#endif
+ rb = rb_new(4, 1, 0);
+ r = rb_write(rb, s, sizeof(s));
+ mt_fail(r == 3);
+ r = rb_read(rb, d, sizeof(d));
+ mt_fail(r == 3);
+ mt_fok(memcmp(d, e, sizeof(e)));
+ rb_destroy(rb);
+}
+
static void invalid_read_write(void)
{
struct rb *rb;
@@ -293,7 +326,7 @@ static void invalid_read_write(void)
static void invalid_stop(void)
{
struct rb *rb;
- rb = rb_new(4, 1, O_NONBLOCK | O_NONTHREAD);
+ rb = rb_new(4, 1, 0);
mt_ferr(rb_stop(rb), EINVAL);
rb_destroy(rb);
}
@@ -344,7 +377,6 @@ static void single_thread(void)
struct rb *rb;
static unsigned long c;
- int flags;
size_t i;
int rc;
@@ -356,12 +388,7 @@ static void single_thread(void)
recv_buf[i] = 0;
}
- flags = 0;
-#if ENABLE_THREADS
- flags = O_NONBLOCK | O_NONTHREAD;
-#endif
-
- rb = rb_new(t_rblen, t_objsize, flags);
+ rb = rb_new(t_rblen, t_objsize, 0);
written = 0;
read = 0;
@@ -403,7 +430,6 @@ static void single_thread(void)
rb_destroy(rb);
}
-
static void bad_count_value(void)
{
struct rb *rb;
@@ -461,10 +487,8 @@ int main(void)
mt_run(peeking);
mt_run(bad_count_value);
mt_run(invalid_read_write);
-
-#if ENABLE_THREADS
- mt_run(nonthread_without_nonblock);
-#endif
+ mt_run(multithread_flag);
+ mt_run(nonblocking_flag);
mt_return();
}