aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-03 07:01:36 +0100
committerMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-03 07:01:36 +0100
commitad865ec0f28a1801f529e637e22eac48fc604c16 (patch)
treeb45fd74f678436977b233e04f68e880fa92fa36c
parent46727bea4d5c5196e132f21b17e3d80530a32ec8 (diff)
parentdddcc8eae9880e916f80bf43d1a552e093c32de5 (diff)
downloadlibrb-ad865ec0f28a1801f529e637e22eac48fc604c16.tar.gz
librb-ad865ec0f28a1801f529e637e22eac48fc604c16.tar.bz2
librb-ad865ec0f28a1801f529e637e22eac48fc604c16.zip
fix: rb_count and rb_space not being thread-safe
-rw-r--r--include/rb.h4
-rw-r--r--man/rb_overview.74
-rw-r--r--man/rb_space.311
-rw-r--r--rb/rb.c102
-rw-r--r--rb/tests.c39
5 files changed, 141 insertions, 19 deletions
diff --git a/include/rb.h b/include/rb.h
index aa17de8..99816b8 100644
--- a/include/rb.h
+++ b/include/rb.h
@@ -38,7 +38,7 @@ int rb_destroy(struct rb *);
int rb_stop(struct rb *);
size_t rb_discard(struct rb *, size_t);
const char *rb_version(char *, char *, char *);
-size_t rb_count(const struct rb *);
-size_t rb_space(const struct rb *);
+long rb_count(struct rb *);
+long rb_space(struct rb *);
#endif
diff --git a/man/rb_overview.7 b/man/rb_overview.7
index f6581cd..1476fcf 100644
--- a/man/rb_overview.7
+++ b/man/rb_overview.7
@@ -32,9 +32,9 @@ unsigned long " flags ");"
size_t " count ", unsigned long " flags ");"
.BI "int rb_clear(struct rb *" rb ", int " clear ");"
.br
-.BI "size_t rb_count(struct rb *" rb ");"
+.BI "long rb_count(struct rb *" rb ");"
.br
-.BI "size_t rb_space(struct rb *" rb ");"
+.BI "long rb_space(struct rb *" rb ");"
.br
.BI "int rb_stop(struct rb *" rb ");"
.br
diff --git a/man/rb_space.3 b/man/rb_space.3
index 7f8f113..35e2ef1 100644
--- a/man/rb_space.3
+++ b/man/rb_space.3
@@ -8,9 +8,9 @@
.PP
.BI "#include <librb.h>"
.PP
-.BI "size_t rb_count(struct rb *" rb ");"
+.BI "long rb_count(struct rb *" rb ");"
.br
-.BI "size_t rb_space(struct rb *" rb ");"
+.BI "long rb_space(struct rb *" rb ");"
.SH RETURN VALUES
.PP
.BR rb_count (3)
@@ -21,6 +21,13 @@ that are currently stored in buffer, and
returns number of how many
.B elements
you can put on the buffer.
+.SH ERRORS
+.PP
+.TP
+.B EINVAL
+Passed
+.I rb
+object is invalid.
.SH SEE ALSO
.PP
.BR rb_overview (7),
diff --git a/rb/rb.c b/rb/rb.c
index c407f50..8593535 100644
--- a/rb/rb.c
+++ b/rb/rb.c
@@ -90,6 +90,36 @@ struct rb
/* ==========================================================================
+ Calculates number of elements in ring buffer. ns stands for not safe as
+ in there are no checks.
+ ========================================================================== */
+
+
+static size_t rb_count_ns
+(
+ const struct rb *rb /* rb object */
+)
+{
+ return (rb->head - rb->tail) & (rb->count - 1);
+}
+
+
+/* ==========================================================================
+ Calculates how many elements can be pushed into ring buffer. ns stands
+ for nos safe as in there are no checks.
+ ========================================================================== */
+
+
+static size_t rb_space_ns
+(
+ const struct rb *rb /* rb object */
+)
+{
+ return (rb->tail - (rb->head + 1)) & (rb->count - 1);
+}
+
+
+/* ==========================================================================
Calculates number of elements in ring buffer until the end of buffer
memory. If elements don't overlap memory, function acts like rb_count
========================================================================== */
@@ -174,7 +204,7 @@ static long rb_recvs
unsigned char* buf; /* buffer treated as unsigned char type */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
- if (count > (rbcount = rb_count(rb)))
+ if (count > (rbcount = rb_count_ns(rb)))
{
/*
* Caller requested more data then is available, adjust count
@@ -271,7 +301,7 @@ static long rb_recvt
pthread_mutex_lock(&rb->lock);
- while (rb_count(rb) == 0 && rb->force_exit == 0)
+ while (rb_count_ns(rb) == 0 && rb->force_exit == 0)
{
struct timespec ts; /* timeout for pthread_cond_timedwait */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -390,7 +420,7 @@ static long rb_sends
(void)flags;
- if (count > (rbspace = rb_space(rb)))
+ if (count > (rbspace = rb_space_ns(rb)))
{
/*
* Caller wants to store more data then there is space available
@@ -475,7 +505,7 @@ long rb_sendt
pthread_mutex_lock(&rb->lock);
- while (rb_space(rb) == 0 && rb->force_exit == 0)
+ while (rb_space_ns(rb) == 0 && rb->force_exit == 0)
{
struct timespec ts; /* timeout for pthread_cond_timedwait */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
@@ -1015,7 +1045,7 @@ size_t rb_discard
#endif
cnte = rb_count_end(rb);
- rbcount = rb_count(rb);
+ rbcount = rb_count_ns(rb);
if (count > rbcount)
{
@@ -1072,28 +1102,74 @@ const char* rb_version
/* ==========================================================================
- Calculates number of elements in ring buffer
+ Returns number of elements in buffer.
========================================================================== */
-size_t rb_count
+long rb_count
(
- const struct rb *rb /* rb object */
+ struct rb *rb /* rb object */
)
{
- return (rb->head - rb->tail) & (rb->count - 1);
+ size_t count; /* number of elements in buffer */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+ VALID(EINVAL, rb);
+ VALID(EINVAL, rb->buffer);
+
+#if ENABLE_THREADS
+ if ((rb->flags & O_NONBLOCK) == 0)
+ {
+ pthread_mutex_lock(&rb->lock);
+ }
+#endif
+
+ count = rb_count_ns(rb);
+
+#if ENABLE_THREADS
+ if ((rb->flags & O_NONBLOCK) == 0)
+ {
+ pthread_mutex_unlock(&rb->lock);
+ }
+#endif
+
+ return (long)count;
}
/* ==========================================================================
- Calculates how many elements can be pushed into ring buffer
+ Return number of free space in buffer
========================================================================== */
-size_t rb_space
+long rb_space
(
- const struct rb *rb /* rb object */
+ struct rb *rb /* rb object */
)
{
- return (rb->tail - (rb->head + 1)) & (rb->count - 1);
+ size_t space; /* number of free slots in buffer */
+ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
+
+
+ VALID(EINVAL, rb);
+ VALID(EINVAL, rb->buffer);
+
+#if ENABLE_THREADS
+ if ((rb->flags & O_NONBLOCK) == 0)
+ {
+ pthread_mutex_lock(&rb->lock);
+ }
+#endif
+
+ space = rb_space_ns(rb);
+
+#if ENABLE_THREADS
+ if ((rb->flags & O_NONBLOCK) == 0)
+ {
+ pthread_mutex_unlock(&rb->lock);
+ }
+#endif
+
+ return (long)space;
}
diff --git a/rb/tests.c b/rb/tests.c
index 067581d..db3d3ef 100644
--- a/rb/tests.c
+++ b/rb/tests.c
@@ -527,6 +527,44 @@ static void discard(void)
}
}
+static void count_and_space(void)
+{
+ char d[4];
+ struct rb *rb;
+
+ rb = rb_new(16, 1, 0);
+
+ mt_fail(rb_space(rb) == 15);
+ mt_fail(rb_count(rb) == 0);
+
+ rb_write(rb, "123", 3);
+
+ mt_fail(rb_space(rb) == 12);
+ mt_fail(rb_count(rb) == 3);
+
+ rb_write(rb, "1234567", 7);
+
+ mt_fail(rb_space(rb) == 5);
+ mt_fail(rb_count(rb) == 10);
+
+ rb_read(rb, d, 4);
+
+ mt_fail(rb_space(rb) == 9);
+ mt_fail(rb_count(rb) == 6);
+
+ rb_discard(rb, 5);
+
+ mt_fail(rb_space(rb) == 14);
+ mt_fail(rb_count(rb) == 1);
+
+ rb_discard(rb, 999);
+
+ mt_fail(rb_space(rb) == 15);
+ mt_fail(rb_count(rb) == 0);
+
+ rb_destroy(rb);
+}
+
static void bad_count_value(void)
{
struct rb *rb;
@@ -588,6 +626,7 @@ int main(void)
mt_run(nonblocking_flag);
mt_run(singlethread_eagain);
mt_run(discard);
+ mt_run(count_and_space);
#if ENABLE_THREADS
mt_run(multithread_eagain);