diff options
author | Michał Łyszczek <michal.lyszczek@bofc.pl> | 2018-02-01 08:14:14 +0100 |
---|---|---|
committer | Michał Łyszczek <michal.lyszczek@bofc.pl> | 2018-02-01 08:14:14 +0100 |
commit | 6a7e8cf9a3cefb162a2c78b2f22c004693081acd (patch) | |
tree | 122bf7e177ce91e051ea6e139f28a0aa972b0e95 | |
parent | 37cc2ad02f5e7e75f5eec5b3fd23500b89879c58 (diff) | |
parent | e66d7bac550bbf3be263132a1fa4dfd568ab885f (diff) | |
download | librb-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.h | 2 | ||||
-rw-r--r-- | man/rb_new.3 | 50 | ||||
-rw-r--r-- | man/rb_overview.7 | 32 | ||||
-rw-r--r-- | rb/rb.c | 47 | ||||
-rw-r--r-- | rb/tests.c | 62 |
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) @@ -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) @@ -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(); } |