From b87a06581ebdb9435224f72a75a1ed6104a7b428 Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Mon, 7 Jan 2019 23:00:40 +0100 Subject: kern/cbuf: update from upstream --- kern/cbuf.c | 77 +++++++++++++++++++++++++++++++++++++++++++------------------ kern/cbuf.h | 40 +++++++++++++++++++++++++++----- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/kern/cbuf.c b/kern/cbuf.c index fcfcc1d5..fc59dc9e 100644 --- a/kern/cbuf.c +++ b/kern/cbuf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017 Richard Braun. + * Copyright (c) 2015-2018 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,21 +50,28 @@ cbuf_index(const struct cbuf *cbuf, size_t abs_index) static void cbuf_update_start(struct cbuf *cbuf) { - /* Mind integer overflows */ if (cbuf_size(cbuf) > cbuf->capacity) { cbuf->start = cbuf->end - cbuf->capacity; } } +static void +cbuf_update_end(struct cbuf *cbuf) +{ + if (cbuf_size(cbuf) > cbuf->capacity) { + cbuf->end = cbuf->start + cbuf->capacity; + } +} + int cbuf_push(struct cbuf *cbuf, const void *buf, size_t size, bool erase) { - size_t free_size; - if (!erase) { - free_size = cbuf_capacity(cbuf) - cbuf_size(cbuf); + size_t avail_size; + + avail_size = cbuf_avail_size(cbuf); - if (size > free_size) { + if (size > avail_size) { return EAGAIN; } } @@ -90,12 +97,12 @@ cbuf_pop(struct cbuf *cbuf, void *buf, size_t *sizep) int cbuf_pushb(struct cbuf *cbuf, uint8_t byte, bool erase) { - size_t free_size; - if (!erase) { - free_size = cbuf_capacity(cbuf) - cbuf_size(cbuf); + size_t avail_size; + + avail_size = cbuf_avail_size(cbuf); - if (free_size == 0) { + if (avail_size == 0) { return EAGAIN; } } @@ -116,7 +123,11 @@ cbuf_popb(struct cbuf *cbuf, void *bytep) } ptr = bytep; - *ptr = cbuf->buf[cbuf_index(cbuf, cbuf->start)]; + + if (ptr) { + *ptr = cbuf->buf[cbuf_index(cbuf, cbuf->start)]; + } + cbuf->start++; return 0; } @@ -127,20 +138,21 @@ cbuf_write(struct cbuf *cbuf, size_t index, const void *buf, size_t size) uint8_t *start, *end, *buf_end; size_t new_end, skip; - if (!cbuf_range_valid(cbuf, index, cbuf->end)) { + if (!cbuf_index_valid(cbuf, index)) { return EINVAL; } new_end = index + size; - if (!cbuf_range_valid(cbuf, cbuf->start, new_end)) { + if (!cbuf_index_valid(cbuf, new_end)) { cbuf->end = new_end; + cbuf_update_start(cbuf); - if (size > cbuf_capacity(cbuf)) { - skip = size - cbuf_capacity(cbuf); + if (size > cbuf->capacity) { + skip = size - cbuf->capacity; buf += skip; index += skip; - size = cbuf_capacity(cbuf); + size = cbuf->capacity; } } @@ -148,7 +160,7 @@ cbuf_write(struct cbuf *cbuf, size_t index, const void *buf, size_t size) end = start + size; buf_end = cbuf->buf + cbuf->capacity; - if ((end <= cbuf->buf) || (end > buf_end)) { + if ((end < cbuf->buf) || (end > buf_end)) { skip = buf_end - start; memcpy(start, buf, skip); buf += skip; @@ -157,7 +169,6 @@ cbuf_write(struct cbuf *cbuf, size_t index, const void *buf, size_t size) } memcpy(start, buf, size); - cbuf_update_start(cbuf); return 0; } @@ -167,8 +178,7 @@ cbuf_read(const struct cbuf *cbuf, size_t index, void *buf, size_t *sizep) const uint8_t *start, *end, *buf_end; size_t size; - /* At least one byte must be available */ - if (!cbuf_range_valid(cbuf, index, index + 1)) { + if (!cbuf_index_valid(cbuf, index)) { return EINVAL; } @@ -186,12 +196,33 @@ cbuf_read(const struct cbuf *cbuf, size_t index, void *buf, size_t *sizep) size = *sizep; } else { size = buf_end - start; - memcpy(buf, start, size); - buf += size; + + if (buf) { + memcpy(buf, start, size); + buf += size; + } + start = cbuf->buf; size = *sizep - size; } - memcpy(buf, start, size); + if (buf) { + memcpy(buf, start, size); + } + return 0; } + +void +cbuf_set_start(struct cbuf *cbuf, size_t start) +{ + cbuf->start = start; + cbuf_update_end(cbuf); +} + +void +cbuf_set_end(struct cbuf *cbuf, size_t end) +{ + cbuf->end = end; + cbuf_update_start(cbuf); +} diff --git a/kern/cbuf.h b/kern/cbuf.h index 38215c16..417a3b9f 100644 --- a/kern/cbuf.h +++ b/kern/cbuf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017 Richard Braun. + * Copyright (c) 2015-2018 Richard Braun. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,7 +18,7 @@ * http://git.sceen.net/rbraun/librbraun.git/ * * - * Circular byte buffer. + * FIFO circular byte buffer. */ #ifndef KERN_CBUF_H @@ -85,6 +85,13 @@ cbuf_range_valid(const struct cbuf *cbuf, size_t start, size_t end) && ((cbuf->end - end) <= cbuf_size(cbuf))); } +static inline bool +cbuf_index_valid(const struct cbuf *cbuf, size_t index) +{ + return ((index - cbuf->start) <= cbuf_size(cbuf)) + && ((cbuf->end - index) <= cbuf_size(cbuf)); +} + /* * Initialize a circular buffer. * @@ -105,10 +112,13 @@ int cbuf_push(struct cbuf *cbuf, const void *buf, size_t size, bool erase); * Pop data from a circular buffer. * * On entry, the sizep argument points to the size of the output buffer. - * On exit, it is updated to the number of bytes actually transferred. + * On return, it is updated to the number of bytes actually transferred. + * + * If the buffer is empty, EAGAIN is returned, and the size of the output + * buffer is unmodified. * - * If the buffer is empty, EAGAIN is returned, and the size of the - * output buffer is undefined. + * The output buffer may be NULL, in which case this function acts as if + * it wasn't, but without writing output data. */ int cbuf_pop(struct cbuf *cbuf, void *buf, size_t *sizep); @@ -124,6 +134,9 @@ int cbuf_pushb(struct cbuf *cbuf, uint8_t byte, bool erase); * Pop a byte from a circular buffer. * * If the buffer is empty, EAGAIN is returned. + * + * The output byte pointer may be NULL, in which case this function acts + * as if it wasn't, but without writing output data. */ int cbuf_popb(struct cbuf *cbuf, void *bytep); @@ -140,12 +153,27 @@ int cbuf_write(struct cbuf *cbuf, size_t index, const void *buf, size_t size); * Read from a circular buffer at a specific location. * * On entry, the sizep argument points to the size of the output buffer. - * On exit, it is updated to the number of bytes actually transferred. + * On return, it is updated to the number of bytes actually transferred. * * If the given index is outside buffer boundaries, EINVAL is returned. * * The circular buffer isn't changed by this operation. + * + * The output buffer may be NULL, in which case this function acts as if + * it wasn't, but without writing output data. */ int cbuf_read(const struct cbuf *cbuf, size_t index, void *buf, size_t *sizep); +/* + * Set the value of the start/end index. + * + * These functions provide low level access to the circular buffer boundaries + * while making sure its size doesn't exceed its capacity. + * + * Users should try and find a higher level way to manipulate the circular + * buffer, and only resort to using these functions if there's no other choice. + */ +void cbuf_set_start(struct cbuf *cbuf, size_t start); +void cbuf_set_end(struct cbuf *cbuf, size_t end); + #endif /* KERN_CBUF_H */ -- cgit v1.2.3