From e785da6cb3643fef61b1609a8a6dcc6e0f7652d3 Mon Sep 17 00:00:00 2001 From: Matheus Date: Tue, 9 May 2023 00:13:51 -0300 Subject: [PATCH] kernel: file_t, fd_t and a few helper functions --- kernel-src/fs/file.c | 125 ++++++++++++++++++++++++++ kernel-src/include/kernel/file.h | 27 ++++++ kernel-src/include/kernel/scheduler.h | 4 + kernel-src/sys/scheduler.c | 11 +++ 4 files changed, 167 insertions(+) create mode 100644 kernel-src/fs/file.c create mode 100644 kernel-src/include/kernel/file.h diff --git a/kernel-src/fs/file.c b/kernel-src/fs/file.c new file mode 100644 index 00000000..d318f258 --- /dev/null +++ b/kernel-src/fs/file.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include + +// TODO have a limit for the fd table + +static scache_t *filecache; +#define FILE_HOLD(f) __atomic_add_fetch(&(f)->refcount, 1, __ATOMIC_SEQ_CST) + +#define FILE_RELEASE(f) \ + if (__atomic_sub_fetch(&(f)->refcount, 1, __ATOMIC_SEQ_CST) == 0) {\ + cleanfile(f); \ + } + +static void ctor(scache_t *cache, void *obj) { + file_t *file = obj; + file->vnode = NULL; + MUTEX_INIT(&file->mutex); + file->refcount = 1; + file->offset = 0; +} + +static file_t* newfile() { + if (filecache == NULL) { + filecache = slab_newcache(sizeof(file_t), 0, ctor, ctor); + __assert(filecache); + } + + return slab_allocate(filecache); +} + +static void cleanfile(file_t *file) { + __assert(!"UNIMPLEMENTED"); +} + +file_t *fd_get(int fd) { + proc_t *proc = _cpu()->thread->proc; + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->fdlock); + + file_t *file = fd < proc->fdcount ? proc->fd[fd].file : NULL; + if (file) + FILE_HOLD(file); + + spinlock_release(&proc->fdlock); + interrupt_set(intstatus); + + if (file) + MUTEX_ACQUIRE(&file->mutex, false); + + return file; +} + +void fd_release(file_t *file) { + MUTEX_RELEASE(&file->mutex); + FILE_RELEASE(file); +} + +int fd_new(vnode_t *vnode, int flags, file_t **rfile, int *rfd) { + file_t *file = newfile(); + if (file == NULL) + return ENOMEM; + + proc_t *proc = _cpu()->thread->proc; + spinlock_acquire(&proc->fdlock); + + // find first free fd + int fd = -1; + for (fd = proc->fdfirst; fd < proc->fdcount && proc->fd[fd].file; ++fd); + + // resize table if not found + if (fd == -1) { + void *newtable = realloc(proc->fd, sizeof(fd_t) * (proc->fdcount + 1)); + if (newtable == NULL) { + spinlock_release(&proc->fdlock); + cleanfile(file); + return ENOMEM; + } + + proc->fd = newtable; + fd = proc->fdcount; + ++proc->fdcount; + } + + proc->fdfirst = fd + 1; + proc->fd[fd].file = file; + proc->fd[fd].flags = flags; + MUTEX_ACQUIRE(&file->mutex, false); + FILE_HOLD(file); + + spinlock_release(&proc->fdlock); + + VOP_HOLD(vnode); + file->vnode = vnode; + *rfile = file; + *rfd = fd; + return 0; +} + +int fd_close(int fd) { + proc_t *proc = _cpu()->thread->proc; + bool intstatus = interrupt_set(false); + spinlock_acquire(&proc->fdlock); + + file_t *file = fd < proc->fdcount ? proc->fd[fd].file : NULL; + if (file) { + proc->fd[fd].file = NULL; + proc->fdfirst = fd; + } + + spinlock_release(&proc->fdlock); + interrupt_set(intstatus); + + if (file) { + FILE_RELEASE(file); + } + else { + return EBADF; + } + + return 0; +} diff --git a/kernel-src/include/kernel/file.h b/kernel-src/include/kernel/file.h new file mode 100644 index 00000000..5005d15c --- /dev/null +++ b/kernel-src/include/kernel/file.h @@ -0,0 +1,27 @@ +#ifndef FILE_H +#define FILE_H + +#include +#include + +typedef struct file_t { + vnode_t *vnode; + mutex_t mutex; + int refcount; + mode_t mode; + uintmax_t offset; + int flags; +} file_t; + +typedef struct fd_t { + file_t *file; + int flags; +} fd_t; + +file_t *fd_get(int fd); +void fd_release(file_t *file); +int fd_new(vnode_t *node, int flags, file_t **file, int *fd); +int fd_close(int fd); +int fd_dup(int oldfd, int newfd, bool exact, int flags, int *ret); + +#endif diff --git a/kernel-src/include/kernel/scheduler.h b/kernel-src/include/kernel/scheduler.h index 234482d5..e361aa5c 100644 --- a/kernel-src/include/kernel/scheduler.h +++ b/kernel-src/include/kernel/scheduler.h @@ -42,6 +42,10 @@ typedef struct proc_t { thread_t **threads; size_t threadtablesize; size_t runningthreadcount; + size_t fdcount; + uintmax_t fdfirst; + spinlock_t fdlock; + struct fd_t *fd; mode_t umask; int flags; vnode_t *cwd; diff --git a/kernel-src/sys/scheduler.c b/kernel-src/sys/scheduler.c index 69c95d0b..605b2a21 100644 --- a/kernel-src/sys/scheduler.c +++ b/kernel-src/sys/scheduler.c @@ -7,6 +7,7 @@ #include #include #include +#include #define QUANTUM_US 100000 #define SCHEDULER_STACK_SIZE 4096 @@ -39,6 +40,16 @@ proc_t *sched_newproc() { proc->threadtablesize = 1; proc->runningthreadcount = 1; SPINLOCK_INIT(proc->lock); + proc->fdcount = 3; + proc->fdfirst = 3; + SPINLOCK_INIT(proc->fdlock); + + proc->fd = alloc(sizeof(fd_t) * 3); + if (proc->fd == NULL) { + free(proc->threads); + slab_free(processcache, proc); + return NULL; + } return proc; }