diff options
-rw-r--r-- | kern/cbuf.c | 87 | ||||
-rw-r--r-- | kern/cbuf.h | 21 | ||||
-rw-r--r-- | kern/log.c | 5 |
3 files changed, 98 insertions, 15 deletions
diff --git a/kern/cbuf.c b/kern/cbuf.c index ef5c7e3..83032e5 100644 --- a/kern/cbuf.c +++ b/kern/cbuf.c @@ -17,6 +17,7 @@ #include <assert.h> #include <stddef.h> +#include <string.h> #include <kern/cbuf.h> #include <kern/error.h> @@ -42,18 +43,23 @@ cbuf_index(const struct cbuf *cbuf, size_t abs_index) return abs_index & (cbuf->capacity - 1); } -void -cbuf_push(struct cbuf *cbuf, char byte) +static void +cbuf_update_start(struct cbuf *cbuf) { - cbuf->buf[cbuf_index(cbuf, cbuf->end)] = byte; - cbuf->end++; - /* Mind integer overflows */ if (cbuf_size(cbuf) > cbuf->capacity) { cbuf->start = cbuf->end - cbuf->capacity; } } +void +cbuf_push(struct cbuf *cbuf, char byte) +{ + cbuf->buf[cbuf_index(cbuf, cbuf->end)] = byte; + cbuf->end++; + cbuf_update_start(cbuf); +} + int cbuf_pop(struct cbuf *cbuf, char *bytep) { @@ -67,13 +73,76 @@ cbuf_pop(struct cbuf *cbuf, char *bytep) } int -cbuf_read(const struct cbuf *cbuf, size_t index, char *bytep) +cbuf_write(struct cbuf *cbuf, size_t index, const char *buf, size_t size) { - /* Mind integer overflows */ - if ((cbuf->end - index - 1) >= cbuf_size(cbuf)) { + char *start, *end, *buf_end; + size_t new_end, skip; + + if ((cbuf->end - index) > cbuf_size(cbuf)) { + return ERROR_INVAL; + } + + new_end = index + size; + + if ((new_end - cbuf->start) > cbuf_size(cbuf)) { + cbuf->end = new_end; + + if (size > cbuf_capacity(cbuf)) { + skip = size - cbuf_capacity(cbuf); + buf += skip; + index += skip; + size = cbuf_capacity(cbuf); + } + } + + start = &cbuf->buf[cbuf_index(cbuf, index)]; + end = start + size; + buf_end = cbuf->buf + cbuf->capacity; + + if (end > buf_end) { + skip = buf_end - start; + memcpy(start, buf, skip); + buf += skip; + start = cbuf->buf; + size -= skip; + } + + memcpy(start, buf, size); + cbuf_update_start(cbuf); + return 0; +} + +int +cbuf_read(const struct cbuf *cbuf, size_t index, char *buf, size_t *sizep) +{ + const char *start, *end, *buf_end; + size_t size; + + size = cbuf->end - index; + + /* At least one byte must be available */ + if ((size - 1) >= cbuf_size(cbuf)) { return ERROR_INVAL; } - *bytep = cbuf->buf[cbuf_index(cbuf, index)]; + if (*sizep > size) { + *sizep = size; + } + + start = &cbuf->buf[cbuf_index(cbuf, index)]; + end = start + *sizep; + buf_end = cbuf->buf + cbuf->capacity; + + if (end <= buf_end) { + size = *sizep; + } else { + size = buf_end - start; + memcpy(buf, start, size); + buf += size; + start = cbuf->buf; + size = *sizep - size; + } + + memcpy(buf, start, size); return 0; } diff --git a/kern/cbuf.h b/kern/cbuf.h index b675fd5..0cac54a 100644 --- a/kern/cbuf.h +++ b/kern/cbuf.h @@ -92,12 +92,25 @@ void cbuf_push(struct cbuf *cbuf, char byte); int cbuf_pop(struct cbuf *cbuf, char *bytep); /* - * Read a byte at a specific location. + * Write into a circular buffer at a specific location. * * If the given index is outside buffer boundaries, ERROR_INVAL is returned. - * Otherwise the byte is stored at the bytep address and 0 is returned. - * The buffer isn't changed by this operation. + * Otherwise size bytes are copied into the circular buffer. If the range + * in the circular buffer goes beyond its end, the end index is updated as + * appropriate. If the buffer is full when extending its end, the oldest + * bytes are overwritten and the start index is updated accordingly. */ -int cbuf_read(const struct cbuf *cbuf, size_t index, char *bytep); +int cbuf_write(struct cbuf *cbuf, size_t index, const char *buf, size_t size); + +/* + * Read from a circular buffer at a specific location. + * + * If the given index is outside buffer boundaries, ERROR_INVAL is returned. + * Otherwise at most *sizep bytes are copied into the given character buffer, + * and *sizep is updated to the number of bytes actually copied. + * + * The circular buffer isn't changed by this operation. + */ +int cbuf_read(const struct cbuf *cbuf, size_t index, char *buf, size_t *sizep); #endif /* _KERN_CBUF_H */ @@ -144,8 +144,8 @@ log_record_consume(struct log_record *record, char c, size_t *sizep) static int log_record_init_consume(struct log_record *record, unsigned long *indexp) { + size_t size, c_size; bool marker_found; - size_t size; int error; char c; @@ -161,7 +161,8 @@ log_record_init_consume(struct log_record *record, unsigned long *indexp) break; } - error = cbuf_read(&log_cbuf, *indexp, &c); + c_size = 1; + error = cbuf_read(&log_cbuf, *indexp, &c, &c_size); if (error) { *indexp = cbuf_start(&log_cbuf); |