diff options
author | Michał Łyszczek <michal.lyszczek@gmail.com> | 2017-04-18 22:29:55 +0200 |
---|---|---|
committer | Michał Łyszczek <michal.lyszczek@gmail.com> | 2017-04-18 22:29:55 +0200 |
commit | eb6b25867353986030ff3b87daef87849a3a873f (patch) | |
tree | fbe518de81ac12d680b5c829704f202d074ff320 /rb.c | |
parent | e9b490f3c8e651f31c7c5886b1f3352625179ee4 (diff) | |
download | librb-eb6b25867353986030ff3b87daef87849a3a873f.tar.gz librb-eb6b25867353986030ff3b87daef87849a3a873f.tar.bz2 librb-eb6b25867353986030ff3b87daef87849a3a873f.zip |
Many changes that includes:
* Code refactor
* Added possibility to completly ignore pthreads making libc the only
dependency
* Better compability with c89
* Changed license from BSD3 to BSD2
* Wrote better documentation
Diffstat (limited to 'rb.c')
-rw-r--r-- | rb.c | 1152 |
1 files changed, 553 insertions, 599 deletions
@@ -1,805 +1,759 @@ -/***************************************************************************** - * Licensed under BSD 3-clause license. See LICENSE file for more information. - * Author: Michał Łyszczek <michal.lyszczek@bofc.pl> - ****************************************************************************/ +/*$2 + =============================================================================== + Licensed under BSD 2-clause license. See LICENSE file for more information. + Author: Michał Łyszczek <michal.lyszczek@bofc.pl> + =============================================================================== + */ + + +/*$2- Included Files =========================================================*/ -/***************************************************************************** - * Included Files - ****************************************************************************/ #include "rb.h" #include <errno.h> -#include <pthread.h> #include <stddef.h> #include <stdlib.h> #include <string.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/socket.h> + +#ifdef LIBRB_PTHREAD +# include <pthread.h> +# include <sys/socket.h> +# include <fcntl.h> +#endif #include "version.h" -/***************************************************************************** - * Private Functions - ****************************************************************************/ -/***************************************************************************** - * Name: rb_count_end - * - * Description: - * Calculates number of elements in ring buffer until the end of buffer - * memory. If elements don't overlap memory, function acts like rb_count - ****************************************************************************/ +/*$2- Private Functions ======================================================*/ + -static size_t rb_count_end(const struct rb *rb) +/* + ------------------------------------------------------------------------------- + Calculates number of elements in ring buffer until the end of buffer + memory. If elements don't overlap memory, function acts like rb_count + ------------------------------------------------------------------------------- + */ + +static size_t rb_count_end( + const struct rb* rb) /* rb object */ { - size_t end = rb->count - rb->tail; - size_t n = (rb->head + end) & (rb->count - 1); - return n < end ? n : end; + /*~~~~~~~~*/ + size_t end; + size_t n; + /*~~~~~~~~*/ + + end = rb->count - rb->tail; + n = (rb->head + end) & (rb->count - 1); + + return n < end ? n : end; } -/***************************************************************************** - * Name: rb_space_end - * - * Description: - * Calculates how many elements can be pushed into ring buffer without - * overlapping memory - ****************************************************************************/ +/* + ------------------------------------------------------------------------------- + Calculates how many elements can be pushed into ring buffer without + overlapping memory + ------------------------------------------------------------------------------- + */ -static size_t rb_space_end(const struct rb *rb) +static size_t rb_space_end( + const struct rb* rb) /* rb object */ { - size_t end = rb->count - 1 - rb->head; - size_t n = (end + rb->tail) & (rb->count - 1); - return n <= end ? n : end + 1; + /*~~~~~~~~*/ + size_t end; + size_t n; + /*~~~~~~~~*/ + + end = rb->count - 1 - rb->head; + n = (end + rb->tail) & (rb->count - 1); + + return n <= end ? n : end + 1; } -/***************************************************************************** - * Name: rb_is_power_of_two - * - * Description: - * Checks if number x is exactly power of two number (ie. 1, 2, 4, 8, 16) - * - * Input Parameters: - * x: number to check - * - * Return Values: - * 0: x is NOT a power of two number - * 1: x is a power of two number - ****************************************************************************/ - -static int rb_is_power_of_two(size_t x) +/* + ------------------------------------------------------------------------------- + Checks if number x is exactly power of two number (ie. 1, 2, 4, 8, 16) + ------------------------------------------------------------------------------- + */ + +static int rb_is_power_of_two( + size_t x) /* number to check */ { - return ((x != 0) && ((x & (~x + 1)) == x)); + return (x != 0) && ((x & (~x + 1)) == x); } -/***************************************************************************** - * Name: rb_recv - * - * Description: - * 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. 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 same data. - * - * Input Parameters: - * rb: ring buffer object - * buffer: memory where copy data from ring buffer - * count: maximum count of objects read into buffer - * flags: - * MSG_PEEK: just copy data without removing them from ring buffer - * - * Return Values: - * Number of bytes copied into buffer, function cannot fail - ****************************************************************************/ - -static ssize_t rb_recvs(struct rb *rb, void *buffer, size_t count, int flags) +/* + ------------------------------------------------------------------------------- + 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.~ + 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 same data. + ------------------------------------------------------------------------------- + */ + +static long rb_recvs( + struct rb* rb, /* rb object */ + void* buffer, /* buffer where received data will be copied to */ + size_t count, /* requested number of elements to copy to buffer */ + unsigned long flags) /* receiving options */ { - size_t rbcount; - size_t cnte; - size_t tail; - size_t objsize; - uint8_t *buf = (uint8_t *)buffer; - - if (count > (rbcount = rb_count(rb))) + /*~~~~~~~~~~~~~~~~~~~~~~*/ + size_t rbcount; /* number of elements in rb */ + size_t cnte; /* number of elements in rb until overlap */ + size_t tail; /* copy of rb->tail in case we need to restore + * it */ + size_t objsize; /* size, in bytes, of single object in rb */ + unsigned char* buf; /* buffer treated as unsigned char type */ + /*~~~~~~~~~~~~~~~~~~~~~~*/ + + if (count > (rbcount = rb_count(rb))) { - /* Caller requested more data then is available, adjust count */ + /* Caller requested more data then is available, adjust count */ - count = rbcount; + count = rbcount; } - objsize = rb->object_size; - tail = rb->tail; - cnte = rb_count_end(rb); + objsize = rb->object_size; + tail = rb->tail; + cnte = rb_count_end(rb); + buf = buffer; - if (count > cnte) + if (count > cnte) { - /* Memory overlaps, copy data in two turns */ + /* Memory overlaps, copy data in two turns */ - memcpy(buf, rb->buffer + rb->tail * objsize, objsize * cnte); - memcpy(buf + cnte * objsize, rb->buffer, (count - cnte) * objsize); - rb->tail = count - cnte; + memcpy(buf, rb->buffer + rb->tail * objsize, objsize * cnte); + memcpy(buf + cnte * objsize, rb->buffer, (count - cnte) * objsize); + rb->tail = count - cnte; } - else + else { - /* Memory doesn't overlap, good we can do copying on one go */ + /* Memory doesn't overlap, good we can do copying on one go */ - memcpy(buf, rb->buffer + rb->tail * objsize, count * objsize); - rb->tail += count; - rb->tail &= rb->count - 1; + memcpy(buf, rb->buffer + rb->tail * objsize, count * objsize); + rb->tail += count; + rb->tail &= rb->count - 1; } - if (flags & MSG_PEEK) + if (flags & MSG_PEEK) { - /* Caller is just peeking, restore previous tail position */ + /* Caller is just peeking, restore previous tail position */ - rb->tail = tail; + rb->tail = tail; } - return count; + return count; } -/***************************************************************************** - * Name: rb_read - * - * Description: - * Reads count data from rb into buffer. Function will block until count - * elements are stored into buffer, unless blocking flag is set to 1. When - * rb is exhausted and there is still data to read, caller thread will be - * put to sleep and will be waked up as soon as there is data in rb. count - * can be any size, it can be much bigger than rb size, just keep in mind if - * count is too big, time waiting for data might be 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. - * - * Input Parameters: - * rb: ring buffer object to work on - * buffer: place where you want data to be copied to - * count: number fo elements (not bytes) you want to be copied - * flags: - * MSG_DONTWAIT: same as setting ring buffer to O_NONBLOCK but works only - * for single call. - * - * Return Values: - * count: all requested data were read into buffer - * <count: only part of requested count elements were copied into buffer - * -1: this value is returned when buffer object is being destroyed - * - * errno: - * EAGAIN: in case of return value <count - ****************************************************************************/ - -static ssize_t rb_recvt(struct rb *rb, void *buffer, size_t count, int flags) +#ifdef LIBRB_PTHREAD + + +/* + ------------------------------------------------------------------------------- + Reads count data from rb into buffer. Function will block until count + elements are stored into buffer, unless blocking flag is set to 1. When rb + is exhausted and there is still data to read, caller thread will be put to + sleep and will be waked up as soon as there is data in rb. count can be any + size, it can be much bigger than rb size, just keep in mind if count is too + big, time waiting for data might be 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. + ------------------------------------------------------------------------------- + */ + +static long rb_recvt( + struct rb* rb, /* rb object */ + void* buffer, /* buffer where received data will be copied to */ + size_t count, /* requested number of elements to copy to buffer */ + unsigned long flags) /* receiving options */ { - size_t read = 0; - uint8_t *buf = (uint8_t *)buffer; + /*~~~~~~~~~~~~~~~~~~~*/ + size_t read; /* number of elements read */ + unsigned char* buf; /* buffer treated as unsigned char type */ + /*~~~~~~~~~~~~~~~~~~~*/ + + read = 0; + buf = buffer; - while (count) + while (count) { - size_t count_to_end; - size_t count_to_read; - size_t bytes_to_read; + /*~~~~~~~~~~~~~~~~~~*/ + size_t count_to_end; + size_t count_to_read; + size_t bytes_to_read; + /*~~~~~~~~~~~~~~~~~~*/ - pthread_mutex_lock(&rb->lock); + pthread_mutex_lock(&rb->lock); - while (rb_count(rb) == 0 && rb->force_exit == 0) + while (rb_count(rb) == 0 && rb->force_exit == 0) { - if (rb->flags & O_NONBLOCK || flags & MSG_DONTWAIT) + if (rb->flags & O_NONBLOCK || flags & MSG_DONTWAIT) { - /* Socket is nonblocking or caller wants just this call to be - * nonblocking, either way, return */ - - pthread_mutex_unlock(&rb->lock); - errno = EAGAIN; - return read; + /* + * Socket is nonblocking or caller wants just this call to be + * nonblocking, either way, return + */ + + pthread_mutex_unlock(&rb->lock); + errno = EAGAIN; + return read; } - /* Buffer is empty, socket is blocking, wait for data */ + /* Buffer is empty, socket is blocking, wait for data */ - pthread_cond_wait(&rb->wait_data, &rb->lock); + pthread_cond_wait(&rb->wait_data, &rb->lock); } - if (rb->force_exit) + if (rb->force_exit) { - /* ring buffer is going down operations on buffer are not allowed */ + /* ring buffer is going down operations on buffer are not allowed */ - pthread_mutex_unlock(&rb->lock); - return -1; + pthread_mutex_unlock(&rb->lock); + return -1; } - /* Elements in memory can overlap, so we need to calculate how much - * elements we can safely read */ + /* + * Elements in memory can overlap, so we need to calculate how much + * elements we can safel + */ - count_to_end = rb_count_end(rb); - count_to_read = count > count_to_end ? count_to_end : count; - bytes_to_read = count_to_read * rb->object_size; + count_to_end = rb_count_end(rb); + count_to_read = count > count_to_end ? count_to_end : count; + bytes_to_read = count_to_read * rb->object_size; - memcpy(buf, rb->buffer + rb->tail * rb->object_size, bytes_to_read); + memcpy(buf, rb->buffer + rb->tail * rb->object_size, bytes_to_read); - /* Adjust pointers and counts for the next read */ + /* Adjust pointers and counts for the next read */ - buf += bytes_to_read; - rb->tail += count_to_read; - rb->tail &= rb->count - 1; - read += count_to_read; - count -= count_to_read; + buf += bytes_to_read; + rb->tail += count_to_read; + rb->tail &= rb->count - 1; + read += count_to_read; + count -= count_to_read; - /* Signal any threads that waits for space to put data in buffer */ + /* Signal any threads that waits for space to put data in buffer */ - pthread_cond_signal(&rb->wait_room); - pthread_mutex_unlock(&rb->lock); + pthread_cond_signal(&rb->wait_room); + pthread_mutex_unlock(&rb->lock); } - return read; + return read; } -/***************************************************************************** - * Name: rb_send - * - * Description: - * 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 - * - * Input Parameters: - * rb: ring buffer object - * buffer: data to copy to ring buffer - * count: maximum count of objects to copy to ring buffer - * flags: non right now - * - * Return Values: - * Number of objects stored into ring buffer. Function cannot fail - ****************************************************************************/ - -static ssize_t rb_sends(struct rb *rb, const void *buffer, size_t count, - int flags) +#endif + +/* + ------------------------------------------------------------------------------- + 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 + ------------------------------------------------------------------------------- + */ + +static long rb_sends( + struct rb* rb, /* rb object */ + const void* buffer, /* location of data to put into rb */ + size_t count, /* requested number of elements to put on the rb */ + unsigned long flags) /* receiving options */ { - size_t rbspace; - size_t spce; - size_t objsize; - const uint8_t *buf = (const uint8_t *)buffer; - - if (count > (rbspace = rb_space(rb))) + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + size_t rbspace; /* space left in rb */ + size_t spce; /* space left in rb until overlap */ + size_t objsize; /* size of a single element in rb */ + const unsigned char* buf; /* buffer treated as unsigned char */ + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + (void)flags; + + if (count > (rbspace = rb_space(rb))) { - /* Caller wants to store more data then there is space available */ + /* Caller wants to store more data then there is space available */ - count = rbspace; + count = rbspace; } - objsize = rb->object_size; - spce = rb_space_end(rb); + objsize = rb->object_size; + spce = rb_space_end(rb); + buf = buffer; - if (count > spce) + if (count > spce) { - /* Memory overlaps, copy data in two turns */ + /* Memory overlaps, copy data in two turns */ - memcpy(rb->buffer + rb->head * objsize, buf, spce * objsize); - memcpy(rb->buffer, buf + spce * objsize, (count - spce) * objsize); - rb->head = count - spce; + memcpy(rb->buffer + rb->head * objsize, buf, spce * objsize); + memcpy(rb->buffer, buf + spce * objsize, (count - spce) * objsize); + rb->head = count - spce; } - else + else { - /* Memory doesn't overlap, good, we can do copying in one go */ + /* Memory doesn't overlap, good, we can do copying in one go */ - memcpy(rb->buffer + rb->head * objsize, buf, count * objsize); - rb->head += count; - rb->head &= rb->count - 1; + memcpy(rb->buffer + rb->head * objsize, buf, count * objsize); + rb->head += count; + rb->head &= rb->count - 1; } - return count; + return count; } -/***************************************************************************** - * Name: rb_write - * - * Description: - * Writes count data pointed by buffer in to rb. Function will block until - * count elements are stored into rb, unless blocking flag is set to 1. When - * rb is full and there is still data to write, caller thread will be put to - * sleep and will be waked up as soon as there is space in rb. count can be - * any size, it can be much bigger than rb size, just keep in mind 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. - * - * Input Parameters: - * rb: ring buffer object to work on - * buffer: location from where data are stored into rb - * count: number of elements caller desires to store into rb - * flags: - * MSG_DONTWAIT acts like rb was O_NONBLOCK, but only for this call - * - * Return Values: - * count: all requested data were written into rb - * <count: only part of requested count elements were copied into rb - * -1: this value is returned when buffer object is being destroyed - * - * errno: - * EAGAIN: in case of return value <count - ****************************************************************************/ - -ssize_t rb_sendt(struct rb *rb, const void *buffer, size_t count, int flags) +#ifdef LIBRB_PTHREAD + + +/* + ------------------------------------------------------------------------------- + Writes count data pointed by buffer in to rb. Function will block until + count elements are stored into rb, unless blocking flag is set to 1. When + rb is full and there is still data to write, caller thread will be put to + sleep and will be waked up as soon as there is space in rb. count can be + any size, it can be much bigger than rb size, just keep in mind 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. + ------------------------------------------------------------------------------- + */ + +long rb_sendt( + struct rb* rb, /* rb object */ + const void* buffer, /* location of data to put into rb */ + size_t count, /* requested number of elements to put on the rb */ + unsigned long flags) /* receiving options */ { - size_t written = 0; - const uint8_t *buf = (const uint8_t *)buffer; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + size_t written; /* number of bytes written to rb */ + const unsigned char* buf; /* buffer treated as unsigned char type */ + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + written = 0; + buf = buffer; - while (count) + while (count) { - size_t count_to_end; - size_t count_to_write; - size_t bytes_to_write; + /*~~~~~~~~~~~~~~~~~~~*/ + size_t count_to_end; + size_t count_to_write; + size_t bytes_to_write; + /*~~~~~~~~~~~~~~~~~~~*/ - pthread_mutex_lock(&rb->lock); + pthread_mutex_lock(&rb->lock); - while (rb_space(rb) == 0 && rb->force_exit == 0) + while (rb_space(rb) == 0 && rb->force_exit == 0) { - if (rb->flags & O_NONBLOCK || flags & MSG_DONTWAIT) + if (rb->flags & O_NONBLOCK || flags & MSG_DONTWAIT) { - pthread_mutex_unlock(&rb->lock); - errno = EAGAIN; - return written; + pthread_mutex_unlock(&rb->lock); + errno = EAGAIN; + return written; } - /* Buffer is full, wait for someone to read data and free space */ + /* Buffer is full, wait for someone to read data and free space */ - pthread_cond_wait(&rb->wait_room, &rb->lock); + pthread_cond_wait(&rb->wait_room, &rb->lock); } - if (rb->force_exit == 1) + if (rb->force_exit == 1) { - /* ring buffer is going down operations on buffer are not allowed */ + /* ring buffer is going down operations on buffer are not allowed */ - pthread_mutex_unlock(&rb->lock); - return -1; + pthread_mutex_unlock(&rb->lock); + return -1; } - /* Count might be too large to store it in one burst, we calculate how - * many elements can we store before needing to overlap memory */ + /* + * Count might be too large to store it in one burst, we calculate + * how many elements can we store before needing to overlap memor + */ - count_to_end = rb_space_end(rb); - count_to_write = count > count_to_end ? count_to_end : count; - bytes_to_write = count_to_write * rb->object_size; + count_to_end = rb_space_end(rb); + count_to_write = count > count_to_end ? count_to_end : count; + bytes_to_write = count_to_write * rb->object_size; - memcpy(rb->buffer + rb->head * rb->object_size, buf, bytes_to_write); + memcpy(rb->buffer + rb->head * rb->object_size, buf, bytes_to_write); - /* Adjust pointers and counts for next write */ + /* Adjust pointers and counts for next write */ - buf += bytes_to_write; - rb->head += count_to_write; - rb->head &= rb->count - 1; - written += count_to_write; - count -= count_to_write; + buf += bytes_to_write; + rb->head += count_to_write; + rb->head &= rb->count - 1; + written += count_to_write; + count -= count_to_write; - /* Signal any threads that waits for data to read */ + /* Signal any threads that waits for data to read */ - pthread_cond_signal(&rb->wait_data); - pthread_mutex_unlock(&rb->lock); + pthread_cond_signal(&rb->wait_data); + pthread_mutex_unlock(&rb->lock); } - return written; + return written; } -/***************************************************************************** - * Public Functions - ****************************************************************************/ - -/***************************************************************************** - * Name: rb_new - * - * Description: - * Initializes ring buffer and alocates necessary resources - * - * Input Parameters: - * rb: ring buffer structure where data will be stored - * count: number of elements (not bytes!) that buffer can hold. It MUST be a - * value that is a power of two (ie 16, 32 or 4096) - * object_size: size, in bytes, of the objects that will be put into buffer - * Once declared cannot be changed, and data must always be of this size, - * or undefinied behaviours will occur. - * flags: - * O_NONBLOCK: if set function will not block when resources are not - * available. Otherwise thread will go to sleep until resoures are - * available again (just like any blocking socket) - * O_NONTHREAD: ring buffer will not use any of pthread functions and will - * work entirely in userspace - note: no sleeping and blocking calls - * possible, must be passed with O_NONBLOCK - * - * Return Values: - * 0: success - * -1: failure - * - * errno: - * EINVAL: rb is null or count is not a power of two number - * - * Function can also return errno values from: - * * malloc - * * pthread_mutex_init - * * pthread_cond_init - * Check proper man pages for details - ****************************************************************************/ - -int rb_new(struct rb *rb, size_t count, size_t object_size, uint32_t flags) +#endif + + +/*$2- Public Functions =======================================================*/ + + +/* + ------------------------------------------------------------------------------- + Initializes ring buffer and allocates all necessary resources. Newly + created rb will be stored in sturct pointer by 'rb'. In case of an function + error, state of 'rb' object is undefinied + ------------------------------------------------------------------------------- + */ + +int rb_new( + struct rb* rb, /* ring buffer to initialize */ + size_t count, /* number of elements (not bytes) that + * buffer can hold */ + size_t object_size, /* size, in bytes, of a single object */ + unsigned long flags) /* flags to create buffer with */ { - int errnos; + /*~~*/ +#ifdef LIBRB_PTHREAD + int e; /* holds errno value */ +#endif + /*~~*/ - if (rb == NULL || rb_is_power_of_two(count) == 0) + if (rb == NULL || rb_is_power_of_two(count) == 0) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - if ((rb->buffer = malloc(count * object_size)) == NULL) + if ((rb->buffer = malloc(count * object_size)) == NULL) { - errnos = errno; - goto error; + errno = ENOMEM; + return -1; } - rb->head = 0; - rb->tail = 0; - rb->count = count; - rb->object_size = object_size; - rb->force_exit = 0; - rb->flags = flags; - - if (flags & O_NONTHREAD) + rb->head = 0; + rb->tail = 0; + rb->count = count; + rb->object_size = object_size; + rb->force_exit = 0; + rb->flags = flags; + +#ifndef LIBRB_PTHREAD + return 0; +#else + if (flags & O_NONTHREAD) { - if (!(flags & O_NONBLOCK)) + if (!(flags & O_NONBLOCK)) { - /* O_NONBLOCK is not set, but it should if O_NONTHREAD is used */ + /* O_NONBLOCK is not set, but it should if O_NONTHREAD is used */ - errnos = EINVAL; - goto error; + e = EINVAL; + goto error; } - rb->recv = rb_recvs; - rb->send = rb_sends; + rb->recv = rb_recvs; + rb->send = rb_sends; - return 0; + return 0; } - /* Multithreaded environment */ + /* Multithreaded environment */ - rb->recv = rb_recvt; - rb->send = rb_sendt; + rb->recv = rb_recvt; + rb->send = rb_sendt; - if (pthread_mutex_init(&rb->lock, NULL)) + if (pthread_mutex_init(&rb->lock, NULL)) { - errnos = errno; - goto error; + e = errno; + goto error; } - if (pthread_cond_init(&rb->wait_data, NULL)) + if (pthread_cond_init(&rb->wait_data, NULL)) { - errnos = errno; - goto error; + e = errno; + goto error; } - if (pthread_cond_init(&rb->wait_room, NULL)) + if (pthread_cond_init(&rb->wait_room, NULL)) { - errnos = errno; - goto error; + e = errno; + goto error; } - return 0; + return 0; error: - pthread_mutex_destroy(&rb->lock); - pthread_cond_destroy(&rb->wait_data); - pthread_cond_destroy(&rb->wait_room); + pthread_mutex_destroy(&rb->lock); + pthread_cond_destroy(&rb->wait_data); + pthread_cond_destroy(&rb->wait_room); - free(rb->buffer); - rb->buffer = NULL; + free(rb->buffer); + rb->buffer = NULL; - errno = errnos; - return -1; + errno = e; + return -1; +#endif } -/***************************************************************************** - * Name: rb_read - * - * Description: - * 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 threaded and blocking, function will block (sleep) caller thread - * until all count elements were copied into buffer. - * - * Function is equivalent to call rb_recv with flags == 0 - * - * Input Parameters: - * rb: ring buffer object - * buffer: place where data will be copied from ring buffer - * count: maximum count of elements to be copied to buffer - * - * Return: - * count: all requested data were read into buffer - * <count: only part of requested count elements were copied into buffer - * -1: error, see errno - * - * errno: - * EINVAL: input parameters are invalid - * EAGAIN: when return is <count - ****************************************************************************/ - -ssize_t rb_read(struct rb *rb, void *buffer, size_t count) +/* + ------------------------------------------------------------------------------- + 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 threaded and blocking, function will block (sleep) caller thread + until all count elements were copied into buffer.~ + Function is equivalent to call rb_recv with flags == 0 + ------------------------------------------------------------------------------- + */ + +long rb_read( + struct rb* rb, /* rb object */ + void* buffer, /* location where data from rb will be stored */ + size_t count) /* requested number of data from rb */ { - if (rb == NULL || buffer == NULL || rb->buffer == NULL) + if (rb == NULL || buffer == NULL || rb->buffer == NULL) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - return rb->recv(rb, buffer, count, 0); +#ifdef LIBRB_PTHREAD + return rb->recv(rb, buffer, count, 0); +#else + return rb_recvs(rb, buffer, count, 0); +#endif } -/***************************************************************************** - * Name: rb_recv - * - * Description: - * Same as rb_read but also accepts flags - * - * Input Parameters: - * rb: ring buffer object - * buffer: place where data will be copied from ring buffer - * count: maximum count of elements to be copied to buffer - * flags: - * MSG_PEEK: copies data into buffer, but doesn't remove them from buffer, - * so subsequent call will return same data. MSG_PEEK can only be used - * with O_NONTHREAD. - * - * Return: - * count: all requested data were read into buffer - * <count: only part of requested count elements were copied into buffer - * -1: error, see errno - * - * errno: - * EINVAL: input parameters are invalid - * EAGAIN: when return is <count - ****************************************************************************/ - -ssize_t rb_recv(struct rb *rb, void *buffer, size_t count, int flags) +/* + ------------------------------------------------------------------------------- + Same as rb_read but also accepts flags + ------------------------------------------------------------------------------- + */ + +long rb_recv( + struct rb* rb, /* rb object */ + void* buffer, /* location where data from rb will be stored */ + size_t count, /* requested number of data from rb */ + unsigned long flags) /* operation flags */ { - if (rb == NULL || buffer == NULL || rb->buffer == NULL) + if (rb == NULL || buffer == NULL || rb->buffer == NULL) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - if (flags & MSG_PEEK && (rb->flags & O_NONTHREAD) != O_NONTHREAD) +#ifdef LIBRB_PTHREAD + if (flags & MSG_PEEK && (rb->flags & O_NONTHREAD) != O_NONTHREAD) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - return rb->recv(rb, buffer, count, flags); + return rb->recv(rb, buffer, count, flags); +#else + return rb_recvs(rb, buffer, count, flags); +#endif } -/***************************************************************************** - * Name: rb_write - * - * Description: - * 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 multithreaded, and blocking function will block (sleep) caller - * until count elements have been stored into rb. - * - * Function os equivalent to call rb_send with flags == 0 - * - * Input Parameters: - * rb: ring buffer object - * buffer: data to copy into rb - * count: number of element to copy into buffer - * - * Return Values: - * count: all data has been commited into rb - * <count: not all data has been stored into rb - * -1: buffer got destroy signal during copying. - * - * errno: - * EINVAL: parameters are invalid - * EAGAIN: in case of return value <count - ****************************************************************************/ - -ssize_t rb_write(struct rb *rb, void *buffer, size_t count) +/* + ------------------------------------------------------------------------------- + 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 multithreaded, and blocking function will block (sleep) caller + until count elements have been stored into rb.~ + Function os equivalent to call rb_send with flags == 0 + ------------------------------------------------------------------------------- + */ + +long rb_write( + struct rb* rb, /* rb object */ + const void* buffer, /* data to be put into rb */ + size_t count) /* requested number of elements to be put into rb */ { - if (rb == NULL || buffer == NULL || rb->buffer == NULL) + if (rb == NULL || buffer == NULL || rb->buffer == NULL) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - return rb->send(rb, buffer, count, 0); +#ifdef LIBRB_PTHREAD + return rb->send(rb, buffer, count, 0); +#else + return rb_sends(rb, buffer, count, 0); +#endif } -/***************************************************************************** - * Name: rb_send - * - * Description: - * Same as rb_write but also accepts flags - * - * Input Parameters: - * rb: ring buffer object - * buffer: data to copy into rb - * count: number of element to copy into buffer - * flags: - * MSG_DONTWAIT acts like rb was O_NONBLOCK, but only for this call - * - * Return Values: - * count: all data has been commited into rb - * <count: not all data has been stored into rb - * -1: buffer got destroy signal during copying. - * - * errno: - * EINVAL: parameters are invalid - * EAGAIN: in case of return value <count - ****************************************************************************/ - -ssize_t rb_send(struct rb *rb, void *buffer, size_t count, int flags) +/* + ------------------------------------------------------------------------------- + Same as rb_write but also accepts flags + ------------------------------------------------------------------------------- + */ + +long rb_send( + struct rb* rb, /* rb object */ + const void* buffer, /* data to be put into rb */ + size_t count, /* requested number of elements to be put into r */ + unsigned long flags) /* operation flags */ { - if (rb == NULL || buffer == NULL || rb->buffer == NULL) + if (rb == NULL || buffer == NULL || rb->buffer == NULL) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - return rb->send(rb, buffer, count, flags); +#ifdef LIBRB_PTHREAD + return rb->send(rb, buffer, count, flags); +#else + return rb_sends(rb, buffer, count, flags); +#endif } -/***************************************************************************** - * Name: rb_clear - * - * Description: - * Clears all data in the buffer - ****************************************************************************/ +/* + ------------------------------------------------------------------------------- + Clears all data in the buffer + ------------------------------------------------------------------------------- + */ -int rb_clear(struct rb *rb) +int rb_clear( + struct rb* rb) /* rb object */ { - if (rb == NULL || rb->buffer == NULL) + if (rb == NULL || rb->buffer == NULL) { - errno = EINVAL; - return -1; + errno = EINVAL; + return -1; } - rb->head = 0; - rb->tail = 0; - return 0; +#ifdef LIBRB_PTHREAD + pthread_mutex_lock(&rb->lock); +#endif + + rb->head = 0; + rb->tail = 0; + +#ifdef LIBRB_PTHREAD + pthread_mutex_unlock(&rb->lock); +#endif + + return 0; } -/***************************************************************************** - * Name: rb_destroy - * - * Description: - * Frees resources allocated by rb_new. Also it stops any blocked rb_read or - * rb_write functions so they can return. - * - * Below only applies to library working in threaded environment - * - * When rb_read and rb_write work in - * another threads and you want to join them after stopping rb, you should - * call this function before joining threads. If you do it otherwise, - * threads calling rb_write or rb_read can be in locked state, waiting for - * resources, and threads might never return to call this function. You have - * been warned - * - * Input Parameters: - * rb: ring buffer object to destroy - * - * Return Values: - * 0: success - * -1: error + errno - * - * Errno: - * EINVAL: rb is not correct - ****************************************************************************/ - -int rb_destroy(struct rb *rb) +/* + ------------------------------------------------------------------------------- + Frees resources allocated by rb_new. Also it stops any blocked rb_read or + rb_write functions so they can return.~ + Below only applies to library working in threaded environment~ + When rb_read and rb_write work in another threads and you want to join them + after stopping rb, you should call this function before joining threads. If + you do it otherwise, threads calling rb_write or rb_read can be in locked + state, waiting for resources, and threads might never return to call this + function. You have been warned + ------------------------------------------------------------------------------- + */ + +int rb_destroy( + struct rb* rb) /* rb object */ { - if (rb == NULL || rb->buffer == NULL) + if (rb == NULL) + { + errno = EINVAL; + return -1; + } + + if (rb->buffer == NULL) { - errno = EINVAL; - return -1; + return 0; } - if (rb->flags & O_NONTHREAD) +#ifdef LIBRB_PTHREAD + if (rb->flags & O_NONTHREAD) { - free(rb->buffer); - rb->buffer = NULL; - return 0; + free(rb->buffer); + rb->buffer = NULL; + return 0; } - rb->force_exit = 1; + rb->force_exit = 1; - /* Signal locked threads in conditional variables to return, so callers can - * exit */ + /* + * Signal locked threads in conditional variables to return, so callers + * can exit + */ - pthread_cond_signal(&rb->wait_data); - pthread_cond_signal(&rb->wait_room); + pthread_cond_signal(&rb->wait_data); + pthread_cond_signal(&rb->wait_room); - /* To prevent any pending operations on buffer, we lock before freeing - * memory, so there is no crash on buffer destroy */ + /* + * To prevent any pending operations on buffer, we lock before freeing + * memory, so there is no crash on buffer destr + */ - pthread_mutex_lock(&rb->lock); - free(rb->buffer); - rb->buffer = NULL; - pthread_mutex_unlock(&rb->lock); + pthread_mutex_lock(&rb->lock); + free(rb->buffer); + rb->buffer = NULL; + pthread_mutex_unlock(&rb->lock); - pthread_mutex_destroy(&rb->lock); - pthread_cond_destroy(&rb->wait_data); - pthread_cond_destroy(&rb->wait_room); + pthread_mutex_destroy(&rb->lock); + pthread_cond_destroy(&rb->wait_data); + pthread_cond_destroy(&rb->wait_room); +#else + free(rb->buffer); + rb->buffer = NULL; +#endif - return 0; + return 0; } -/***************************************************************************** - * Name: rb_version - * - * Description: - * Returns version of the library - * - * Output Parameters: - * major: Major version (API/ABI changes) - * minor: Minor version (Added functions) - * patch: Patch version (bug fixes) - * - * Function also returns pointer to static allocated pointer to char where - * full version string is stored - ****************************************************************************/ - -const char *rb_version(char *major, char *minor, char *patch) +/* + ------------------------------------------------------------------------------- + Returns version of the library + ------------------------------------------------------------------------------- + */ + +const char* rb_version( + char* major, /* major version info will be stored here */ + char* minor, /* minor version info will be stored here */ + char* patch) /* patch version info will be stored here */ { - if (major && minor && patch) + if (major && minor && patch) { - /* strtok modified input string, so we need copy of version */ + /*~~~~~~~~~~~~~~~~~~~~*/ + char version[11 + 1]; /* strtok modified input string, so we need + * copy of version */ + /*~~~~~~~~~~~~~~~~~~~~*/ - char version[11 + 1]; - strcpy(version, VERSION); + strcpy(version, VERSION); - strcpy(major, strtok(version, ".")); - strcpy(minor, strtok(NULL, ".")); - strcpy(patch, strtok(NULL, ".")); + strcpy(major, strtok(version, ".")); + strcpy(minor, strtok(NULL, ".")); + strcpy(patch, strtok(NULL, ".")); } - return VERSION; + return VERSION; } -/***************************************************************************** - * Name: rb_count - * - * Description: - * Calculates number of elements in ring buffer - ****************************************************************************/ +/* + ------------------------------------------------------------------------------- + Calculates number of elements in ring buffer + ------------------------------------------------------------------------------- + */ -size_t rb_count(const struct rb *rb) +size_t rb_count( + const struct rb* rb) /* rb object */ { - return (rb->head - rb->tail) & (rb->count - 1); + return (rb->head - rb->tail) & (rb->count - 1); } -/***************************************************************************** - * Name: rb_space - * - * Description: - * Calculates how many elements can be pushed into ring buffer - ****************************************************************************/ +/* + ------------------------------------------------------------------------------- + Calculates how many elements can be pushed into ring buffer + ------------------------------------------------------------------------------- + */ -size_t rb_space(const struct rb *rb) +size_t rb_space( + const struct rb* rb) /* rb object */ { - return (rb->tail - (rb->head + 1)) & (rb->count -1 ); + return (rb->tail - (rb->head + 1)) & (rb->count - 1); } - - |