diff options
-rw-r--r-- | AUTHORS | 1 | ||||
l--------- | COPYING | 1 | ||||
-rw-r--r-- | INSTALL | 25 | ||||
-rw-r--r-- | LICENSE | 31 | ||||
-rw-r--r-- | Makefile | 45 | ||||
-rw-r--r-- | rb.c | 462 | ||||
-rw-r--r-- | rb.h | 174 | ||||
-rw-r--r-- | readme.md | 120 | ||||
-rw-r--r-- | version.h | 6 |
9 files changed, 865 insertions, 0 deletions
@@ -0,0 +1 @@ +Michał Łyszczek <michal.lyszczek@bofc.pl> @@ -0,0 +1 @@ +LICENSE
\ No newline at end of file @@ -0,0 +1,25 @@ +Requirements: + + * libc (glibc, uclibc) + * pthread + +Install locally: + +make && make install + +Cross Compile: + +To compile for different architecture 3 env variables should be set + +CC - cross compiler +INC - staging include directory +LINC - staging library directory + +Example make might look like this + +$ CC=arm-none-eabi \ + INC=-I/usr/arm-none-eabi/usr/include \ + LINC=-L/usr/arm-none-eabi/usr/lib \ + make + +$ INSTALL_DIR=/usr/arm-none-eabi/usr make install @@ -0,0 +1,31 @@ +/***************************************************************************** + * Copyright (C) 2016 Michał Łyszczek. All rights reserved. + * Author: Michał Łyszczek <michal.lyszczek@gmail.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NAME nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + ****************************************************************************/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cbdfb57 --- /dev/null +++ b/Makefile @@ -0,0 +1,45 @@ +LIBS = -lpthread +SRCS = rb.c +MAIN = librb + +STD = -std=c89 +WARN = -Wall -Wextra -pedantic -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wwrite-strings -Winit-self -Wcast-align -Wstrict-aliasing -Wformat=2 -Wmissing-include-dirs -Wno-unused-parameter -Wuninitialized -Wstrict-overflow=5 -pedantic-errors +CFLAGS = $(STD) $(WARN) -fPIC +LDFLAGS = -shared + +VERSION = `grep "define VERSION" version.h | cut -d \" -f2` +VERSION_MAJOR = `grep "define VERSION" version.h | cut -d \" -f2 | cut -d. -f1` +CC ?= x86_64-pc-linux-gnu-gcc +INSTALL_DIR ?= /usr/local +INC ?= +LINC ?= + +OBJS = $(SRCS:.c=.o) + +.PHONY: depend clean debug release + +all: release + +release: WARN += -Werror +release: CFLAGS += -O2 +release: $(MAIN) + +debug: CFLAGS += -O0 -ggdb -g3 +debug: $(MAIN) + +install: + mkdir -p $(INSTALL_DIR)/include + mkdir -p $(INSTALL_DIR)/lib + cp rb.h $(INSTALL_DIR)/include + cp $(MAIN).so.$(VERSION) $(INSTALL_DIR)/lib + ln -sf $(MAIN).so.$(VERSION) $(INSTALL_DIR)/lib/$(MAIN).so.$(VERSION_MAJOR) + ln -sf $(MAIN).so.$(VERSION) $(INSTALL_DIR)/lib/$(MAIN).so + +clean: + $(RM) *.o *~ $(MAIN).so.$(VERSION) + +$(MAIN): $(OBJS) + $(CC) $(CFLAGS) $(LIBS) $(LINC) $(LDFLAGS) -o $(MAIN).so.$(VERSION) $(OBJS) + +.c.o: + $(CC) $(CFLAGS) $(INC) -c $< -o $@ @@ -0,0 +1,462 @@ +/***************************************************************************** + * Licensed under BSD 3-clause license. See LICENSE file for more information. + * Author: Michał Łyszczek <michal.lyszczek@bofc.pl> + ****************************************************************************/ + +/***************************************************************************** + * 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 "version.h" + +/***************************************************************************** + * Private Functions + ****************************************************************************/ + +/***************************************************************************** + * Name: rb_count + * + * Description: + * Calculates number of elements in ring buffer + ****************************************************************************/ + +static size_t rb_count(const struct rb *rb) +{ + return (rb->head - rb->tail) & (rb->count - 1); +} + +/***************************************************************************** + * Name: rb_space + * + * Description: + * Calculates how many elements can be pushed into ring buffer + ****************************************************************************/ + +static size_t rb_space(const struct rb *rb) +{ + return (rb->tail - (rb->head + 1)) & (rb->count -1 ); +} + +/***************************************************************************** + * 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 + ****************************************************************************/ + +static size_t rb_count_end(const struct rb *rb) +{ + size_t end = rb->count - rb->tail; + size_t 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 + ****************************************************************************/ + +static size_t rb_space_end(const struct rb *rb) +{ + size_t end = rb->count - 1 - rb->head; + size_t 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) +{ + return ((x != 0) && ((x & (~x + 1)) == x)); +} + +/***************************************************************************** + * 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. + * non_blocking: if set to 1, 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) + * + * 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, int non_blocking) +{ + int errnos; + + if (rb == NULL || rb_is_power_of_two(count) == 0) + { + errno = EINVAL; + return -1; + } + + if ((rb->buffer = malloc(count * object_size)) == NULL) + { + errnos = errno; + goto error; + } + + rb->head = 0; + rb->tail = 0; + rb->count = count; + rb->object_size = object_size; + rb->force_exit = 0; + rb->non_blocking = non_blocking; + + if (pthread_mutex_init(&rb->lock, NULL)) + { + errnos = errno; + goto error; + } + + if (pthread_cond_init(&rb->wait_data, NULL)) + { + errnos = errno; + goto error; + } + + if (pthread_cond_init(&rb->wait_room, NULL)) + { + errnos = errno; + goto error; + } + + return 0; + +error: + pthread_mutex_destroy(&rb->lock); + pthread_cond_destroy(&rb->wait_data); + pthread_cond_destroy(&rb->wait_room); + + free(rb->buffer); + rb->buffer = NULL; + + errno = errnos; + return -1; +} + +/***************************************************************************** + * 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 + * + * 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 + ****************************************************************************/ + +ssize_t rb_read(struct rb *rb, void *buffer, size_t count) +{ + size_t read; + uint8_t *buf; + + if (rb == NULL || buffer == NULL || rb->buffer == NULL) + { + errno = EINVAL; + return -1; + } + + read = 0; + buf = (uint8_t *)buffer; + + while (count) + { + size_t count_to_end; + size_t count_to_read; + size_t bytes_to_read; + + pthread_mutex_lock(&rb->lock); + + while (rb_count(rb) == 0 && rb->force_exit == 0) + { + if (rb->non_blocking == 1) + { + pthread_mutex_unlock(&rb->lock); + errno = EAGAIN; + return read; + } + + /* Buffer is empty, wait for data */ + + pthread_cond_wait(&rb->wait_data, &rb->lock); + } + + if (rb->force_exit == 1) + { + /* ring buffer is going down operations on buffer are not allowed */ + + pthread_mutex_unlock(&rb->lock); + return -1; + } + + /* Elements in memory can overlap, so we need to calculate how much + * elements we can safely read */ + + 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); + + /* 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; + + /* Signal any threads that waits for space to put data in buffer */ + + pthread_cond_signal(&rb->wait_room); + pthread_mutex_unlock(&rb->lock); + } + + return read; +} + +/***************************************************************************** + * 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 + * + * 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_write(struct rb *rb, const void *buffer, size_t count) +{ + size_t written; + const uint8_t *buf; + + if (rb == NULL || buffer == NULL || rb->buffer == NULL) + { + errno = EINVAL; + return -1; + } + + written = 0; + buf = (const uint8_t *)buffer; + + while (count) + { + size_t count_to_end; + size_t count_to_write; + size_t bytes_to_write; + + pthread_mutex_lock(&rb->lock); + + while (rb_space(rb) == 0 && rb->force_exit == 0) + { + if (rb->non_blocking == 1) + { + pthread_mutex_unlock(&rb->lock); + errno = EAGAIN; + return written; + } + + /* Buffer is full, wait for someone to read data and free space */ + + pthread_cond_wait(&rb->wait_room, &rb->lock); + } + + if (rb->force_exit == 1) + { + /* ring buffer is going down operations on buffer are not allowed */ + + 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_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); + + /* 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; + + /* Signal any threads that waits for data to read */ + + pthread_cond_signal(&rb->wait_data); + pthread_mutex_unlock(&rb->lock); + } + + return written; +} + +/***************************************************************************** + * 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. 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 + ****************************************************************************/ + +void rb_destroy(struct rb *rb) +{ + if (rb == NULL) + { + errno = EINVAL; + return; + } + + rb->force_exit = 1; + + /* Signal locked threads in conditional variables to return, so callers can + * exit */ + + 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 */ + + 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); +} + +/***************************************************************************** + * 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) +{ + if (major && minor && patch) + { + /* strtok modified input string, so we need copy of version */ + + char version[11 + 1]; + strcpy(version, VERSION); + + strcpy(major, strtok(version, ".")); + strcpy(minor, strtok(NULL, ".")); + strcpy(patch, strtok(NULL, ".")); + } + + return VERSION; +} @@ -0,0 +1,174 @@ +/***************************************************************************** + * Licensed under BSD 3-clause license. See LICENSE file for more information. + * Author: Michał Łyszczek <michal.lyszczek@bofc.pl> + ****************************************************************************/ + +#ifndef LIBRB_H +#define LIBRB_H 1 + +/***************************************************************************** + * Included Files + ****************************************************************************/ + +#include <pthread.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/types.h> + +/***************************************************************************** + * Public Types + ****************************************************************************/ + +struct rb +{ + size_t head; + size_t tail; + size_t count; + size_t object_size; + + uint8_t *buffer; + + pthread_mutex_t lock; + pthread_cond_t wait_data; + pthread_cond_t wait_room; + + uint8_t force_exit; + uint8_t non_blocking; +}; + +/***************************************************************************** + * 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. + * non_blocking: if set to 1, 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) + * + * 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, int non_blocking); + +/***************************************************************************** + * 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 + * + * 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 + ****************************************************************************/ + +ssize_t rb_read(struct rb *rb, void *buffer, size_t 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 + * + * 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_write(struct rb *rb, const void *buffer, size_t count); + +/***************************************************************************** + * 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. 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 + ****************************************************************************/ + +void rb_destroy(struct rb *rb); + +/***************************************************************************** + * 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); + +#endif /* LIBRB_H */ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..b61dcaf --- /dev/null +++ b/readme.md @@ -0,0 +1,120 @@ +About +===== + +This is library that provides fast, easy to use ring buffer. It's interface is +very similar to read/write interface from POSIX. Library has only 4 functions: + + * rb_new - creates new ring buffer + * rb_read - reads from the ring buffer + * rb_write - writes to the ring buffer + * rb_destroy - destroys ring buffer + +Library is thread safe and thread aware. If there are not 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 read and write will return immediately +when there are not enough resources. There is only one malloc and free in new +and destory functions. + +As this library is focused on speed, user can create buffer with only power of +two count (n^2). Thanks to this solution there is much less conditional jumps. +Altough user is limited to number of elements, single element can be any size. +Thanks to that, ring buffer can also be easily used with structs as an item. + +Library is C89 complaint and will work under any POSIX environment that +implements pthreads and libc. + +License +======= + +Library is licensed under BSD 3-clause license. See LICENSE file for details + +Compiling and installing +======================== + +Standard **make** and **make install** should be enough. If you want to +install to different directory, just use **INSTALL_DIR=/custom/path make +install**. + +To compile for different architecture 3 env variables should be set + + * CC - cross compiler + * INC - staging include directory + * LINC - staging library directory + +Example make might look like this + +~~~.sh +$ CC=arm-none-eabi \ + INC=-I/usr/arm-none-eabi/usr/include \ + LINC=-L/usr/arm-none-eabi/usr/lib \ + make +$ INSTALL_DIR=/usr/arm-none-eabi/usr make install +~~~ + +Function descriptions +===================== + +rb_new +------ + +~~~.c +int rb_new(struct rb *rb, size_t count, size_t object_size, int non_blocking); +~~~ + +This function is used to create and initialize new ring buffer. Information +about created ring buffer is stored into memory pointed by rb. User is +responsible to create this structure in his application. This object will be +later used to identify ring buffer. + +count and object_size describes buffer sizes. Library will allocate on callers +heap (count * object_size) bytes. Count must be a power of two number, as +library tries to avoid unecessary conditional jump to improve performance. +Object size determines how big is a single element. This value is constant for +lifetime of a ring buffer. Object size might be for example +**sizeof(uint8_t)** or **sizeof(uint32_t)** or even **sizeof(struct my_msg)**. +In short, object size should be a size of an object ring buffer will hold. You +should not write nor read objects of different size than created one, as this +will lead to undefinied behaviour or even crashes. + +non_blocking defines whether **rb_read** and **rb_write** function should +block or not when there is not enough resources available. + +rb_write and rb_read +-------------------- + +~~~.c +ssize_t rb_write(struct rb *rb, const void *buffer, size_t count); +ssize_t rb_read(struct rb *rb, void *buffer, size_t count); +~~~ + +Functions used read and write elements to the ring buffer. Function will +commit (count * rb->object_size) bytes. Functions can and will try to commit +as many bytes as possible in a single burst, so it is better to call these +function once with big count number than call it in a loop with count == 1. + +When non_blocking flag is not set, every read and write will block until it +commits every element passed to the function. When read or write function +blocks, caller thread is put to sleep to it doesn't use any processor time, +until it is waked by opossite write or read call. Ie. when ring buffer is +full, and user calls **rb_write**, thread will sleep until another thread +calls **rb_read** and makes space for writing operation. When non_blocking +flag is set, and resources are not available, read or write will return +immediately with number of elements commited and EAGAIN errno. Just like with +sockets. + +rb_destroy +---------- + +~~~.c +void rb_destroy(struct rb *rb); +~~~ + +Function frees resources allocated by **rb_new**. Also it forces **rb_write** +and **rb_read** return even in blocking mode, so users thread using them can +be joined. + +Contact +======= + +Michał Łyszczek <michal.lyszczek@bofc.pl> diff --git a/version.h b/version.h new file mode 100644 index 0000000..7d35986 --- /dev/null +++ b/version.h @@ -0,0 +1,6 @@ +#ifndef LIBRB_VERSION_H +#define LIBRB_VERSION_H 1 + +#define VERSION "1.0.0" + +#endif /* LIBRB_VERSION_H */ |