aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-02 18:04:14 +0100
committerMichał Łyszczek <michal.lyszczek@bofc.pl>2018-02-02 18:04:14 +0100
commit5934814945eb4cec144db95bd076814869dbb4f2 (patch)
treee66f94afa9d70eb1912b156e285be7c7163a458f
parent6a7e8cf9a3cefb162a2c78b2f22c004693081acd (diff)
parent295071796a93a628938290beb8e14c0047865271 (diff)
downloadlibrb-5934814945eb4cec144db95bd076814869dbb4f2.tar.gz
librb-5934814945eb4cec144db95bd076814869dbb4f2.tar.bz2
librb-5934814945eb4cec144db95bd076814869dbb4f2.zip
change: return -1 EAGAIN only when buffer is empty/full
To be more posix-complaint, write and read should return -1 and EAGAIN errno only when buffer is full or empty. That's how read/write works.
-rw-r--r--man/rb_read.364
-rw-r--r--man/rb_write.312
-rw-r--r--rb/rb.c48
-rw-r--r--rb/tests.c35
4 files changed, 124 insertions, 35 deletions
diff --git a/man/rb_read.3 b/man/rb_read.3
index 2c48d04..3505599 100644
--- a/man/rb_read.3
+++ b/man/rb_read.3
@@ -26,6 +26,7 @@ to memory pointed by
.PP
Note that by
.B elements
+n
we don't mean
.BR bytes .
For example if
@@ -41,17 +42,46 @@ number than call it in a loop with
.I count
== 1.
.PP
-By default (if buffer wasn't created with
-.B O_NONBLOCK
-flag), every read and will block until it reads all element passed to the
-function.
-When read function blocks, caller thread is put to sleep, so it doesn't use any
-processor time, until it is waked by opossite write call, ie. when ring buffer
-is empty, and user calls
-.BR rb_read (3),
-thread will sleep until another thread calls
+By default buffer works in single-threaded mode.
+In this mode all calls on
+.I rb
+object are non blocking.
+This means if
+.I count
+.B elements
+you want to read is higher than there is inside buffer, function
+will copy only as much
+.B elements
+as there are inside
+.I rb
+and will return.
+If
+.BR read (3)
+is called when buffer is empty,
+.B EAGAIN
+error will be returned.
+.PP
+If library has been built with
+.B pthread
+support, and
+.I rb
+was created with
+.B O_MULTITHREAD
+flag, all functions will be blocking calls.
+That means if you want to copy more
+.B elements
+then there is inside
+.I rb
+object, calling thread will be put to sleep - and thus will use no CPU - until
+someone else calls
.BR rb_write (3)
-and puts some data for read operation.
+to write data to buffer and total
+.I count
+.B elements
+have been copied into
+.IR buffer .
+.I rb
+object in multi-threaded applications without mutexes.
.PP
.BR rb_recv (3)
works the same but it also accepts
@@ -113,22 +143,12 @@ buffer is left intact.
.B EINVAL
Any of the passed pointers is NULL.
.TP
-.B EINVAL
-.B MSG_PEEK
-was passed but
-.I rb
-is operating in multi-threaded mode.
-.TP
.B EAGAIN
This error will be set, when
.I rb
-is operating in non blocking mode, and
+is operating in non blocking mode, and there is no data to be read from
.I rb
-buffer contains less
-.B elements
-than requested by
-.IR count .
-Note, this is not an actual error, and will not happen when function returns -1.
+immediately.
.TP
.B ECANCELED
.BR rb_stop (3)
diff --git a/man/rb_write.3 b/man/rb_write.3
index 856179f..05957da 100644
--- a/man/rb_write.3
+++ b/man/rb_write.3
@@ -36,7 +36,7 @@ is 4 bytes, and
is 3, this will copy 4 * 3 = 12 bytes from
.I buffer
.PP
-Write functions works the same way in multi-threaded mode as read ones.
+Write functions works the same way in multi/single-threaded mode as read ones.
Please see
.BR rb_read (3)
description for more details.
@@ -88,13 +88,11 @@ Any of the passed pointers is NULL
.B EAGAIN
This error will be set, when
.I rb
-is operating in non blocking mode, and
+is operating in non blocking mode, and there is no place in
.I rb
-buffer contains less free
-.B elements
-space than requested by
-.IR count .
-Note, this is not an actual error, and will not happen when function returns -1.
+to write data from
+.I buffer
+immediately
.TP
.B ECANCELED
.BR rb_stop (3)
diff --git a/rb/rb.c b/rb/rb.c
index c885fe8..9e32a92 100644
--- a/rb/rb.c
+++ b/rb/rb.c
@@ -150,7 +150,8 @@ static int rb_is_power_of_two
/* ==========================================================================
Function reads maximum count of data from rb into buffer. When user
requested more data than there is in a buffer, function will copy all
- data from rb and will return number of bytes copied.
+ data from rb and will return number of bytes copied. When there is no
+ data in buffer, function will return -1 and EAGAIN
If MSG_PEEK flag is set, data will be copied into buffer, but tail
pointer will not be moved, so consequent call to rb_recv will return
@@ -182,6 +183,12 @@ static long rb_recvs
count = rbcount;
}
+ if (count == 0)
+ {
+ errno = EAGAIN;
+ return -1;
+ }
+
objsize = rb->object_size;
tail = rb->tail;
cnte = rb_count_end(rb);
@@ -231,7 +238,8 @@ static long rb_recvs
significant. When blocking flag is set to 1, and there is less data in
rb than count expects, function will copy as many elements as it can
(actually it will copy all of data that is in rb) and will return
- with number of elements stored in buffer.
+ with number of elements stored in buffer. When there is no
+ data in buffer, function will return -1 and EAGAIN
========================================================================== */
@@ -277,7 +285,17 @@ static long rb_recvt
if (rb->flags & O_NONBLOCK || flags & MSG_DONTWAIT)
{
pthread_mutex_unlock(&rb->lock);
- errno = EAGAIN;
+
+ if (read == 0)
+ {
+ /*
+ * set errno only when we did not read any bytes from rb
+ * this is how standard posix read/send works
+ */
+
+ errno = EAGAIN;
+ return -1;
+ }
return read;
}
@@ -352,7 +370,7 @@ static long rb_recvt
Function writes maximum count of data into ring buffer from buffer. If
there is not enough space to store all data from buffer, function will
store as many as it can, and will return count of objects stored into
- rin buffer
+ ring buffer. If buffer is full, function returns -1 and EAGAIN error.
========================================================================== */
@@ -381,6 +399,12 @@ static long rb_sends
count = rbspace;
}
+ if (count == 0)
+ {
+ errno = EAGAIN;
+ return -1;
+ }
+
objsize = rb->object_size;
spce = rb_space_end(rb);
buf = buffer;
@@ -419,7 +443,8 @@ static long rb_sends
if count is too big, time waiting for space might be significant. When
blocking flag is set to 1, and there is less space in rb than count
expects, function will copy as many elements as it can and will return
- with number of elements written to rb.
+ with number of elements written to rb. If buffer is full, function
+ returns -1 and EAGAIN error.
========================================================================== */
@@ -464,7 +489,18 @@ long rb_sendt
if (rb->flags & O_NONBLOCK || flags & MSG_DONTWAIT)
{
pthread_mutex_unlock(&rb->lock);
- errno = EAGAIN;
+
+ if (written == 0)
+ {
+ /*
+ * set errno only when we did not read any bytes from rb
+ * this is how standard posix read/send works
+ */
+
+ errno = EAGAIN;
+ return -1;
+ }
+
return written;
}
diff --git a/rb/tests.c b/rb/tests.c
index f7537b6..a93cabe 100644
--- a/rb/tests.c
+++ b/rb/tests.c
@@ -264,6 +264,21 @@ static void multi_thread(void)
free(recv_buf);
}
+static void multithread_eagain(void)
+{
+ char s[6] = {0, 1, 2, 3, 4, 5};
+ char d[6];
+ struct rb *rb;
+
+ rb = rb_new(4, 1, O_MULTITHREAD | O_NONBLOCK);
+ rb_write(rb, s, sizeof(s));
+ mt_ferr(rb_write(rb, s, sizeof(s)), EAGAIN);
+ rb_read(rb, d, sizeof(d));
+ mt_ferr(rb_read(rb, d, sizeof(d)), EAGAIN);
+ rb_destroy(rb);
+
+}
+
#endif
@@ -310,6 +325,21 @@ static void nonblocking_flag(void)
rb_destroy(rb);
}
+static void singlethread_eagain(void)
+{
+ char s[6] = {0, 1, 2, 3, 4, 5};
+ char d[6];
+ struct rb *rb;
+
+ rb = rb_new(4, 1, 0);
+ rb_write(rb, s, sizeof(s));
+ mt_ferr(rb_write(rb, s, sizeof(s)), EAGAIN);
+ rb_read(rb, d, sizeof(d));
+ mt_ferr(rb_read(rb, d, sizeof(d)), EAGAIN);
+ rb_destroy(rb);
+}
+
+
static void invalid_read_write(void)
{
struct rb *rb;
@@ -489,6 +519,11 @@ int main(void)
mt_run(invalid_read_write);
mt_run(multithread_flag);
mt_run(nonblocking_flag);
+ mt_run(singlethread_eagain);
+
+#if ENABLE_THREADS
+ mt_run(multithread_eagain);
+#endif
mt_return();
}