kernel: file_t, fd_t and a few helper functions

This commit is contained in:
Matheus
2023-05-09 00:13:51 -03:00
parent 8913f80a0c
commit e785da6cb3
4 changed files with 167 additions and 0 deletions
+125
View File
@@ -0,0 +1,125 @@
#include <kernel/file.h>
#include <kernel/slab.h>
#include <kernel/interrupt.h>
#include <logging.h>
#include <errno.h>
#include <kernel/alloc.h>
// 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;
}