From 8c247352543c50204314efeb988f9f59d84f5019 Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Tue, 16 Dec 2014 22:35:09 +0100 Subject: Add simple reference counted buffer structure. --- kernel/Makefile | 3 +- kernel/include/buffer.h | 38 +++++++++++ kernel/include/thread.h | 3 +- kernel/l0/thread.c | 2 +- kernel/lib/buffer.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 3 deletions(-) create mode 100644 kernel/include/buffer.h create mode 100644 kernel/lib/buffer.c 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 +#include + +// 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 + +#include +#include + +#include + +// 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 :*/ -- cgit v1.2.3