From e28d965ea11e3e3126dcae6588c3a24f68e79cc9 Mon Sep 17 00:00:00 2001 From: Julian Barathieu Date: Sun, 24 Mar 2019 22:51:16 +0100 Subject: [PATCH] Buffer stuff --- Makefile | 6 +- kaleid/crtlib/mem.c | 1 + kaleid/include/base/crtlib.h | 1 + kaleid/include/base/errno.h | 2 +- kaleid/include/kernel/buf.h | 113 +++++++++++++++ kaleid/kernel/buf/buf.c | 263 +++++++++++++++++++++++++++++++++++ 6 files changed, 384 insertions(+), 2 deletions(-) create mode 100644 kaleid/include/kernel/buf.h create mode 100644 kaleid/kernel/buf/buf.c diff --git a/Makefile b/Makefile index 9ffbd33..ff578a4 100644 --- a/Makefile +++ b/Makefile @@ -128,7 +128,8 @@ kal_kern_obj= $(KOBJDIR)/kernel/cpuid.o $(KOBJDIR)/kernel/init.o \ $(KOBJDIR)/kernel/table.o $(KOBJDIR)/kernel/cursor.o \ $(KOBJDIR)/kernel/term.o $(KOBJDIR)/kernel/vga.o \ $(KOBJDIR)/kernel/panic.o $(KOBJDIR)/kernel/map.o \ - $(KOBJDIR)/kernel/heap.o $(KOBJDIR)/kernel/malloc.o + $(KOBJDIR)/kernel/heap.o $(KOBJDIR)/kernel/malloc.o \ + $(KOBJDIR)/kernel/buf.o $(KOBJDIR)/kernel/cpuid.o: $(KERNELDIR)/kernel/cpu/cpuid.c $(KERNELDIR)/include/*/*.h @$(KCC) $< -o $@ @@ -160,6 +161,9 @@ $(KOBJDIR)/kernel/heap.o: $(KERNELDIR)/kernel/mm/heap.c $(KERNELDIR)/include/*/* $(KOBJDIR)/kernel/malloc.o: $(KERNELDIR)/kernel/mm/malloc.c $(KERNELDIR)/include/*/*.h @$(KCC) $< -o $@ @echo ${CL2}[$@] ${CL}Compiled.${CL3} +$(KOBJDIR)/kernel/buf.o: $(KERNELDIR)/kernel/buf/buf.c $(KERNELDIR)/include/*/*.h + @$(KCC) $< -o $@ + @echo ${CL2}[$@] ${CL}Compiled.${CL3} ## MISC MAKEFILE ------------------------------------------------------------- # ./ProjectTree: ./.stylehlp_sh diff --git a/kaleid/crtlib/mem.c b/kaleid/crtlib/mem.c index 7d03682..208cffc 100644 --- a/kaleid/crtlib/mem.c +++ b/kaleid/crtlib/mem.c @@ -38,6 +38,7 @@ void *malloc(size_t n) rc = KalAllocMemory(&ptr, n, 0, 0); __set_errno(rc); + (void)rc; return ptr; } diff --git a/kaleid/include/base/crtlib.h b/kaleid/include/base/crtlib.h index 9aa697d..a62aa39 100644 --- a/kaleid/include/base/crtlib.h +++ b/kaleid/include/base/crtlib.h @@ -183,6 +183,7 @@ unsigned long strtoul(const char *restrict, char **restrict, int); //------------------------------------------// +void *calloc(size_t, size_t) __attribute__((__malloc__)); void *malloc(size_t) __attribute__((__malloc__)); void free(void *); diff --git a/kaleid/include/base/errno.h b/kaleid/include/base/errno.h index d063504..a6e2d33 100644 --- a/kaleid/include/base/errno.h +++ b/kaleid/include/base/errno.h @@ -54,7 +54,7 @@ // Not an executable format #define ENOEXEC 8 -// Bad file number +// Bad file #define EBADF 9 // Try again diff --git a/kaleid/include/kernel/buf.h b/kaleid/include/kernel/buf.h new file mode 100644 index 0000000..13520d5 --- /dev/null +++ b/kaleid/include/kernel/buf.h @@ -0,0 +1,113 @@ +//----------------------------------------------------------------------------// +// GNU GPL OS/K // +// // +// Desc: Buffer library // +// // +// // +// Copyright © 2018-2019 The OS/K Team // +// // +// This file is part of OS/K. // +// // +// OS/K is free software: you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation, either version 3 of the License, or // +// any later version. // +// // +// OS/K is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY//without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with OS/K. If not, see . // +//----------------------------------------------------------------------------// + +#ifndef _KALKERN_BASE_H +#include +#endif + +#ifndef _KALKERN_BUF_H +#define _KALKERN_BUF_H + +typedef struct Buffer_t Buffer_t; + +// +// Buffer flags +// +enum +{ + BF_LINE = 1, // Line-buffered + BF_FILE = 2, // Linked to a file + BF_ALLOC = 4, // Buffer was malloc'd + BF_FONCLOSE = 8, // Don't flush on close +}; + +// +// Buffer states +// +enum +{ + BS_CLOSED = 0, // Buffer closed (need allocation) + BS_EOF, // Buffer closed, or end of file reached + BS_ERR, // Buffer not ready, an error happened + + // Buffer ready for... + BS_RDWR, // Both reading and writing + BS_RDONLY, // Only for reading + BS_WRONLY, // Only for writing +}; + +typedef error_t (*BFlusher_t)(Buffer_t *); + +struct Buffer_t +{ + uint initDone; + Lock_t lock; + + int flags; // Buffer flags + int state; // Buffer state + + size_t size; // Current size + + char *buf; // Beginning of buffer + char *rp; // Read pointer + char *wp; // Write pointer + + BFlusher_t flusher; // Called for flushing + + // The following parameters are only used in line buf mode + + int lastLF; // Characters since beginning of line + int lineLen; // Line length (for line buffers) + int nLines; // Number of lines in "true" buffer + // size/(lineLen*nLines) - 1 playback buffers +}; + +extern Buffer_t BStdOut, BStdErr; + +error_t BCloseBuf(Buffer_t *buf); +void BFlushOnClose(Buffer_t *buf); + +Buffer_t *BOpenPureBuf(char *source, size_t size); + +// Creates a lined buffer of pbCount*nLines lines each +// of lineLen length (pb = playback buffer, for scrolling up) +// If source==NULL, malloc the buffer +Buffer_t *BOpenLineBuf(char *source, int mode, int lineLen, + int nLines, int pbCount, BFlusher_t flusher); + +int BGetFlags(Buffer_t *buf); +int BGetState(Buffer_t *buf); +int BGetLineLen(Buffer_t *buf); +void BSetLineLen(Buffer_t *buf, int len); + +void BLockBuf(Buffer_t *buf); +void BUnlockBuf(Buffer_t *buf); +bool BTrylockBuf(Buffer_t *buf); + +error_t BFlushBuf(Buffer_t *buf); +error_t BPutOnBuf(Buffer_t *buf, uchar ch); +error_t BPrintOnBuf(Buffer_t *buf, size_t n, const char *fmt, ...); +error_t BPrintOnBufV(Buffer_t *buf, size_t n, const char *fmt, va_list ap); + +#endif diff --git a/kaleid/kernel/buf/buf.c b/kaleid/kernel/buf/buf.c new file mode 100644 index 0000000..3491ffd --- /dev/null +++ b/kaleid/kernel/buf/buf.c @@ -0,0 +1,263 @@ +//----------------------------------------------------------------------------// +// GNU GPL OS/K // +// // +// Desc: Buffer library // +// // +// // +// Copyright © 2018-2019 The OS/K Team // +// // +// This file is part of OS/K. // +// // +// OS/K is free software: you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation, either version 3 of the License, or // +// any later version. // +// // +// OS/K is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY//without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with OS/K. If not, see . // +//----------------------------------------------------------------------------// + +#include +#include + +// Straightforward functions +int BGetFlags(Buffer_t *buf) { return buf->flags; } +int BGetState(Buffer_t *buf) { return buf->state; } +int BGetLineLen(Buffer_t *buf) { return buf->lineLen; } +void BSetLineLen(Buffer_t *buf, int len) { buf->lineLen = len; } + +void BLockBuf(Buffer_t *buf) +{ + assert(buf && buf->initDone == INITOK); + ExAcquireLock(&buf->lock); +} + +void BUnlockBuf(Buffer_t *buf) { ExReleaseLock(&buf->lock); } +bool BTrylockBuf(Buffer_t *buf) { return ExAttemptLock(&buf->lock); } + +void BFlushOnClose(Buffer_t *buf) { buf->flags |= BF_FONCLOSE; } + +// +// Closes a buffer, not flushing unless the proper flag is set +// +error_t BCloseBuf(Buffer_t *buf) +{ + if (!buf) return EINVAL; + + assert(buf->initDone == INITOK); + ExAcquireLock(&buf->lock); + + if (buf->flags & BF_FONCLOSE) { + BFlushBuf(buf); + } + + if (buf->flags & BF_ALLOC) { + free(buf->buf); + } + + buf->buf = buf->rp = buf->wp = NULL; + buf->initDone = buf->flags = buf->state = buf->size = 0; + + ExReleaseLock(&buf->lock); + KalFreeMemory(buf); + + return EOK; +} + +// +// Opens a pure text buffer (for WRITING only) +// If source==NULL, malloc's the internal buffer +// +#if 0 +Buffer_t *BOpenPureBuf(char *source, size_t size) +{ + /*Buffer_t *buf = malloc(sizeof *buf); + buf->flags = 0; + ExInitLock(&buf->lock);*/ + + return NULL; +} +#endif + +extern BFlusher_t _VGA_BFlusher; + +// +// Creates a lined buffer of (nLines + pbCount*nLines) lines each +// of lineLen length (pb = playback buffer, for scrolling up) +// +Buffer_t *BOpenLineBuf(char *source, int mode, + int lineLen, int nLines, int pbCount, BFlusher_t flusher) +{ + assert(lineLen > 0 && nLines > 0 && pbCount >= 0); + assert(mode == BS_RDWR || mode == BS_RDONLY || mode == BS_WRONLY); + + Buffer_t *buf = malloc(sizeof *buf); + + ExInitLock(&buf->lock, KLOCK_MUTEX); + ExAcquireLock(&buf->lock); + + buf->lastLF = 0; + buf->state = mode; + buf->flags = BF_LINE; + buf->nLines = nLines; + buf->lineLen = lineLen; + buf->size = lineLen * nLines * (pbCount + 1); + + if (source == NULL) { + buf->buf = malloc(buf->size); + } else { + buf->buf = source; + } + + buf->wp = buf->rp = buf->buf; + buf->flusher = flusher; + buf->initDone = INITOK; + + ExReleaseLock(&buf->lock); + return buf; +} + +// +// Flushes a buffer, returns EBADF when not possible +// +error_t BFlushBuf(Buffer_t *buf) +{ + error_t rc; + + assert(buf && buf->initDone == INITOK); + + if (!buf) return EINVAL; + if (!buf->flusher || buf->state == BS_EOF || buf->state == BS_ERR) { + return EBADF; + } + + ExAcquireLock(&buf->lock); + rc = buf->flusher(buf); + ExReleaseLock(&buf->lock); + + return rc; +} + +static error_t bputc(Buffer_t *buf, uchar ch); + +// +// Writes a character on a buffer +// +error_t BPutOnBuf(Buffer_t *buf, uchar ch) +{ + error_t rc; + assert(buf && buf->initDone == INITOK); + + if (!buf) return EINVAL; + if (buf->state != BS_RDWR && buf->state != BS_WRONLY) { + return EBADF; + } + + ExAcquireLock(&buf->lock); + rc = bputc(buf, ch); + ExReleaseLock(&buf->lock); + return rc; +} + +// +// Internal, unlocked version of BPutOnBuf +// +static error_t bputc(Buffer_t *buf, uchar ch) +{ + error_t rc; + size_t bufSize, pbCount; + + // Implements playback / scrolling up when line buffering + // Note that '\n', '\r' and '\t' can never occur in the buffer + // That should change; there should be a flag for it + if (buf->flags & BF_LINE) { + + // Deal with carriage returns + if (ch == '\r') { + buf->wp -= buf->lastLF; + buf->lastLF = 0; + assert(buf->wp >= buf->buf); + } + + // Deal with tabs... we need a tabSize field + // We assume tabs are 4 characters long for now + else if (ch == '\t') { + rc = bputc(buf, ' '); + if (rc > 0) return rc; + + while (buf->lastLF % 4 > 0) { + rc = bputc(buf, ' '); + if (rc > 0) return rc; + } + } + + // Deal with line feeds by filling the rest of the line with spaces + // We need a field for choosing a different filler, e.g. '\0' + else if (ch == '\n') { + assert(buf->lastLF < buf->lineLen); + while (buf->lastLF > 0) { + rc = bputc(buf, ' '); + if (rc > 0) return rc; + } + } + + // Just a regular character + else { + // Do we have to scroll up? + if (buf->wp == buf->buf + buf->size) { + // Yes, so we give up a whole playback buffer worth + // of lines so we don't have to do this too often + // (basically we make the current buffer a pb one) + bufSize = buf->nLines * buf->lineLen; + pbCount = (buf->size / bufSize) - 1; + + // Paranoia check + assert(buf->size >= (size_t)(buf->nLines * buf->lineLen)); + + // If we only have one playback buffer we just give up a line + if (pbCount == 0) { + // Use of memcpy() is safe because the source occur + // after the destination + memcpy(buf->buf, buf->buf + buf->lineLen, + buf->size - buf->lineLen); + buf->wp -= buf->lineLen; + } + + // We do have a playback buffer worth of lines to give up + else { + memcpy(buf->buf, buf->buf + bufSize, + buf->size - bufSize); + buf->wp -= buf->lineLen; + } + } + + // Write the damn thing + *buf->wp++ = (char)ch; + + // Did we reach the end of line? + if (++buf->lastLF == buf->lineLen) { + buf->lastLF = 0; + } + } + + return EOK; + } + + // No scrolling up when not line-buffering + else { + if (buf->wp == buf->buf + buf->size) { + buf->state = BS_EOF; + } + + return ENOSYS; + } +} + +error_t BPrintOnBuf(Buffer_t *buf, size_t n, const char *fmt, ...); +error_t BPrintOnBufV(Buffer_t *buf, size_t n, const char *fmt, va_list ap); +