diff options
author | Michał Łyszczek <michal.lyszczek@bofc.pl> | 2018-02-02 18:04:14 +0100 |
---|---|---|
committer | Michał Łyszczek <michal.lyszczek@bofc.pl> | 2018-02-02 18:04:14 +0100 |
commit | 5934814945eb4cec144db95bd076814869dbb4f2 (patch) | |
tree | e66f94afa9d70eb1912b156e285be7c7163a458f | |
parent | 6a7e8cf9a3cefb162a2c78b2f22c004693081acd (diff) | |
parent | 295071796a93a628938290beb8e14c0047865271 (diff) | |
download | librb-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.3 | 64 | ||||
-rw-r--r-- | man/rb_write.3 | 12 | ||||
-rw-r--r-- | rb/rb.c | 48 | ||||
-rw-r--r-- | rb/tests.c | 35 |
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) @@ -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; } @@ -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(); } |