aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2014-12-16 22:35:09 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2014-12-16 22:35:09 +0100
commit8c247352543c50204314efeb988f9f59d84f5019 (patch)
treeef7d8775c9c51eddbc1e14e57e0e654b350efe7c
parent0cafda1270f765e98c6ab5b298d28fd820b0e68c (diff)
downloadkogata-8c247352543c50204314efeb988f9f59d84f5019.tar.gz
kogata-8c247352543c50204314efeb988f9f59d84f5019.zip
Add simple reference counted buffer structure.
-rw-r--r--kernel/Makefile3
-rw-r--r--kernel/include/buffer.h38
-rw-r--r--kernel/include/thread.h3
-rw-r--r--kernel/l0/thread.c2
-rw-r--r--kernel/lib/buffer.c169
5 files changed, 212 insertions, 3 deletions
diff --git a/kernel/Makefile b/kernel/Makefile
index a981c72..1764764 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,8 @@ CFLAGS = -ffreestanding -O2 -std=gnu99 -Wall -Wextra -I . -I ./include -g -Wno-u
LD = i586-elf-gcc
LDFLAGS = -T linker.ld -ffreestanding -O2 -nostdlib -lgcc -Xlinker -Map=kernel.map
-OBJ = lib/string.o lib/printf.o lib/slab_alloc.o lib/mutex.o lib/hashtbl.o \
+OBJ = lib/string.o lib/printf.o lib/slab_alloc.o lib/mutex.o \
+ lib/hashtbl.o lib/buffer.o\
l0/loader.o l0/kmain.o l0/dbglog.o l0/sys.o \
l0/gdt.o l0/idt.o l0/interrupt.o l0/context_switch.o l0/thread.o \
l0/frame.o l0/paging.o l0/region.o l0/kmalloc.o
diff --git a/kernel/include/buffer.h b/kernel/include/buffer.h
new file mode 100644
index 0000000..577ceae
--- /dev/null
+++ b/kernel/include/buffer.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <stdint.h>
+#include <stddef.h>
+
+// The buffer_t type is a simple reference-counted buffer type
+// enabling the creation, sharing, slicing and concatenation of buffers
+// without having to copy everything each time
+
+// Once a buffer is allocated, its contents is immutable
+
+// Encoding and decoding functions for buffer contents are provided in
+// a separate file (encode.h)
+
+struct buffer;
+typedef struct buffer buffer_t;
+
+void buffer_ref(buffer_t*); // increase reference counter
+void buffer_unref(buffer_t*); // decrease reference counter
+
+size_t buffer_len(buffer_t* buf);
+size_t read_buffer(buffer_t* buf, char* to, size_t begin, size_t n); // returns num of bytes read
+
+buffer_t* buffer_from_bytes(const char* data, size_t n); // bytes are COPIED
+buffer_t* buffer_from_bytes_nocopy(const char* data, size_t n); // bytes are NOT COPIED
+
+// these functions GIVE the buffer in order to create the new buffer, ie they do not increase RC
+// the buffer is NOT GIVED if the new buffer could not be created (ie retval == 0)
+buffer_t* buffer_slice(buffer_t* b, size_t begin, size_t n);
+buffer_t* buffer_concat(buffer_t* a, buffer_t* b);
+
+// these functions KEEP a reference on the buffer (ie RC is incremented)
+// the RC is NOT INCREMENTED if the new buffer cannot be created
+buffer_t* buffer_slice_k(buffer_t* b, size_t begin, size_t n);
+buffer_t* buffer_concat_k(buffer_t* a, buffer_t* b);
+
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/
diff --git a/kernel/include/thread.h b/kernel/include/thread.h
index 4c5f337..757ba00 100644
--- a/kernel/include/thread.h
+++ b/kernel/include/thread.h
@@ -17,6 +17,7 @@ typedef struct saved_context {
void (*eip)();
} saved_context_t;
+struct process;
typedef struct thread {
saved_context_t ctx;
pagedir_t *current_pd_d;
@@ -25,7 +26,7 @@ typedef struct thread {
region_info_t *stack_region;
- void* more_data;
+ struct process *proc; // process : L1 data structure
struct thread *next_in_queue;
} thread_t;
diff --git a/kernel/l0/thread.c b/kernel/l0/thread.c
index bd40cc8..0f5c209 100644
--- a/kernel/l0/thread.c
+++ b/kernel/l0/thread.c
@@ -144,7 +144,7 @@ thread_t *new_thread(entry_t entry, void* data) {
t->current_pd_d = get_kernel_pagedir();
- t->more_data = 0; // free for use by L1 functions
+ t->proc = 0; // used by L1 functions
return t;
}
diff --git a/kernel/lib/buffer.c b/kernel/lib/buffer.c
new file mode 100644
index 0000000..4d168e0
--- /dev/null
+++ b/kernel/lib/buffer.c
@@ -0,0 +1,169 @@
+#include <kmalloc.h>
+
+#include <buffer.h>
+#include <string.h>
+
+#include <sys.h>
+
+// three types of buffers
+#define T_BYTES 1
+#define T_SLICE 2
+#define T_CONCAT 3
+
+struct buffer {
+ uint16_t rc, type; // takes less space like this
+ size_t len;
+ union {
+ struct {
+ const char* data;
+ bool owned;
+ } bytes;
+ struct {
+ struct buffer *buf;
+ size_t begin;
+ } slice;
+ struct {
+ struct buffer *a, *b;
+ } concat;
+ };
+};
+
+void buffer_ref(buffer_t *b) {
+ b->rc++;
+}
+
+void buffer_unref(buffer_t *b) {
+ b->rc--;
+ if (b->rc == 0) {
+ switch (b->type) {
+ case T_BYTES:
+ if (b->bytes.owned) kfree((void*)b->bytes.data);
+ break;
+ case T_SLICE:
+ buffer_unref(b->slice.buf);
+ break;
+ case T_CONCAT:
+ buffer_unref(b->concat.a);
+ buffer_unref(b->concat.b);
+ break;
+ default:
+ ASSERT(false);
+ }
+ kfree(b);
+ }
+}
+
+size_t buffer_size(buffer_t *b) {
+ return b->len;
+}
+
+size_t read_buffer(buffer_t *b, char* dest, size_t begin, size_t n) {
+ if (begin >= b->len) return 0;
+ if (begin + n >= b->len) n = b->len - begin;
+
+ switch (b->type) {
+ case T_BYTES:
+ memcpy(dest, b->bytes.data + begin, n);
+ break;
+ case T_SLICE:
+ read_buffer(b->slice.buf, dest, begin + b->slice.begin, n);
+ break;
+ case T_CONCAT: {
+ size_t la = b->concat.a->len;
+ if (begin < la) {
+ size_t r = read_buffer(b->concat.a, dest, begin, n);
+ if (r < n) {
+ ASSERT(read_buffer(b->concat.b, dest, 0, n - r) == n - r);
+ }
+ } else {
+ ASSERT(read_buffer(b->concat.b, dest, begin - la, n) == n);
+ }
+ break;
+ }
+ default:
+ ASSERT(false);
+ }
+
+ return n;
+}
+
+// ========================= //
+// BUFFER CREATION FUNCTIONS //
+// ========================= //
+
+buffer_t *buffer_from_bytes_nocopy(const char* data, size_t n) {
+ buffer_t *b = (buffer_t*)kmalloc(sizeof(buffer_t));
+ if (b == 0) return 0;
+
+ b->rc = 1;
+ b->type = T_BYTES;
+ b->len = n;
+ b->bytes.data = data;
+ b->bytes.owned = false;
+
+ return b;
+}
+buffer_t *buffer_from_bytes(const char* data, size_t n) {
+ char* data2 = (char*)kmalloc(n);
+ if (data2 == 0) return 0;
+
+ memcpy(data2, data, n);
+
+ buffer_t *b = buffer_from_bytes_nocopy(data2, n);
+ if (b == 0) {
+ kfree(data2);
+ return 0;
+ }
+
+ b->bytes.owned = true;
+
+ return b;
+}
+
+
+buffer_t* buffer_slice(buffer_t* src, size_t begin, size_t n) {
+ if (begin + n > src->len) return 0; // invalid request
+
+ buffer_t *b = (buffer_t*)kmalloc(sizeof(buffer_t));
+ if (b == 0) return 0;
+
+ b->rc = 1;
+ b->type = T_SLICE;
+ b->len = n;
+ b->slice.buf = src;
+ b->slice.begin = begin;
+
+ return b;
+}
+
+buffer_t* buffer_concat(buffer_t* a, buffer_t* b) {
+ buffer_t *r = (buffer_t*)kmalloc(sizeof(buffer_t));
+ if (r == 0) return r;
+
+ r->rc = 1;
+ r->type = T_CONCAT;
+ r->len = a->len + b->len;
+ r->concat.a = a;
+ r->concat.b = b;
+
+ return r;
+}
+
+buffer_t* buffer_slice_k(buffer_t *b, size_t begin, size_t n) {
+ buffer_t *r = buffer_slice(b, begin, n);
+ if (r != 0) {
+ buffer_ref(b);
+ }
+ return r;
+}
+
+buffer_t* buffer_concat_k(buffer_t *a, buffer_t *b) {
+ buffer_t *r = buffer_concat(a, b);
+ if (r != 0) {
+ buffer_ref(a);
+ buffer_ref(b);
+ }
+ return r;
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/