summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kern/cbuf.c87
-rw-r--r--kern/cbuf.h21
-rw-r--r--kern/log.c5
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 */
diff --git a/kern/log.c b/kern/log.c
index a3b34f3..9f95ca8 100644
--- a/kern/log.c
+++ b/kern/log.c
@@ -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);