From 85bd0c0412c65380dc24f73faa1e7d1716a590bc Mon Sep 17 00:00:00 2001 From: Matheus Date: Mon, 10 Oct 2022 10:46:27 -0300 Subject: [PATCH] pipes: initial implementation --- src/fs/fd.c | 29 ++++++++++-- src/fs/tmpfs.c | 2 + src/fs/vfs.c | 11 +++++ src/include/kernel/pipe.h | 21 +++++++++ src/include/kernel/vfs.h | 1 + src/sys/pipe.c | 98 +++++++++++++++++++++++++++++++++++++++ src/sys/syscalls/open.c | 2 - 7 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 src/include/kernel/pipe.h create mode 100644 src/sys/pipe.c diff --git a/src/fs/fd.c b/src/fs/fd.c index de2f531e..991d9a07 100644 --- a/src/fs/fd.c +++ b/src/fs/fd.c @@ -3,6 +3,7 @@ #include #include #include +#include int fd_release(fd_t* fd){ spinlock_release(&fd->lock); @@ -99,18 +100,36 @@ int fd_free(fdtable_t* fdtable, int ifd){ } fd_t* fd = fdtable->fd[ifd]; - spinlock_acquire(&fd->lock); - if(--fd->refcount > 0){ + if(__atomic_sub_fetch(&fd->refcount, 1, __ATOMIC_RELAXED) > 0){ fdtable->fd[ifd] = NULL; spinlock_release(&fd->lock); spinlock_release(&fdtable->lock); return 0; } + + spinlock_acquire(&fd->lock); + fdtable->fd[ifd] = NULL; spinlock_release(&fdtable->lock); + + if(GETTYPE(fd->mode) == TYPE_FIFO){ + pipe_t* pipe = fd->node->objdata; + spinlock_acquire(&pipe->lock); + if(FD_FLAGS_READ & fd->flags){ + pipe->readers--; + event_signal(&pipe->revent, true); + } + if(FD_FLAGS_WRITE & fd->flags){ + pipe->writers--; + event_signal(&pipe->wevent, true); + } + spinlock_release(&pipe->lock); + } + + int err = 0; if(fd->node) err = vfs_close(fd->node); @@ -230,7 +249,7 @@ int fd_duplicate(fdtable_t* table, int src, int dest, int type, int* ret){ destfd = table->fd[dest]; if(destfd){ spinlock_acquire(&destfd->lock); - if(--destfd->refcount == 0){ + if(__atomic_sub_fetch(&destfd->refcount, 1, __ATOMIC_RELAXED) == 0){ if(destfd->node) vfs_close(destfd->node); free(destfd); } @@ -244,12 +263,14 @@ int fd_duplicate(fdtable_t* table, int src, int dest, int type, int* ret){ // everything is set now table->fd[dest] = srcfd; - srcfd->refcount++; + __atomic_add_fetch(&srcfd->refcount, 1, __ATOMIC_RELAXED); + *ret = dest; fd_release(srcfd); spinlock_release(&table->lock); + return 0; } diff --git a/src/fs/tmpfs.c b/src/fs/tmpfs.c index 4d598d50..921b1e3e 100644 --- a/src/fs/tmpfs.c +++ b/src/fs/tmpfs.c @@ -6,6 +6,7 @@ #include #include +fs_t kerneltmpfs; static int tmpfs_mount(dirnode_t* mountpoint, vnode_t* device, int mountflags, void* fsinfo){ @@ -158,5 +159,6 @@ static fscalls_t funcs = { fscalls_t* tmpfs_getfuncs(){ + kerneltmpfs.calls = &funcs; return &funcs; } diff --git a/src/fs/vfs.c b/src/fs/vfs.c index b9a8a94a..962b77cb 100644 --- a/src/fs/vfs.c +++ b/src/fs/vfs.c @@ -6,6 +6,7 @@ #include #include #include +#include dirnode_t* vfsroot; hashtable fsfuncs; @@ -64,6 +65,10 @@ int vfs_write(int* error, vnode_t* node, void* buff, size_t count, size_t offset int type = GETTYPE(node->st.st_mode); + if(type == TYPE_FIFO) + return pipe_write(node->objdata, buff, count, error); + + if(type == TYPE_DIR || type == TYPE_LINK){ *error = EINVAL; return -1; @@ -108,6 +113,10 @@ int vfs_read(int* error, vnode_t* node, void* buff, size_t count, size_t offset) int type = GETTYPE(node->st.st_mode); + if(type == TYPE_FIFO){ + return pipe_read(node->objdata, buff, count, error); + } + if(type == TYPE_DIR || type == TYPE_LINK){ *error = EINVAL; return -1; @@ -135,6 +144,8 @@ int vfs_close(vnode_t* node){ vfs_releasenode(node); int status = 0; + + // TODO free pipe if one if(node->refcount == 0) status = node->fs->calls->close(node); diff --git a/src/include/kernel/pipe.h b/src/include/kernel/pipe.h new file mode 100644 index 00000000..83ba8f69 --- /dev/null +++ b/src/include/kernel/pipe.h @@ -0,0 +1,21 @@ +#ifndef _PIPE_H_INCLUDE +#define _PIPE_H_INCLUDE + +#include +#include +#include +#include + +typedef struct{ + int lock; + event_t revent, wevent; + ringbuffer_t buff; + uintmax_t readers, writers; +} pipe_t; + +pipe_t* pipe_create(size_t buffsize); +void pipe_drestroy(pipe_t* pipe); +int pipe_read(pipe_t* pipe, void* buff, size_t count, int* error); +int pipe_write(pipe_t* pipe, void* buff, size_t count, int* error); + +#endif diff --git a/src/include/kernel/vfs.h b/src/include/kernel/vfs.h index 9176f719..61e067d0 100644 --- a/src/include/kernel/vfs.h +++ b/src/include/kernel/vfs.h @@ -24,6 +24,7 @@ typedef struct _vnode_t { void* fsdata; size_t refcount; struct _dirnode_t* parent; + void* objdata; } vnode_t; // folders are an expansion of vnode_t to save memory diff --git a/src/sys/pipe.c b/src/sys/pipe.c new file mode 100644 index 00000000..54ef2169 --- /dev/null +++ b/src/sys/pipe.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include + +pipe_t* pipe_create(size_t buffsize){ + pipe_t* pipe = alloc(sizeof(pipe_t)); + if(!pipe) + return NULL; + if(ringbuffer_init(&pipe->buff, buffsize)){ + free(pipe); + return NULL; + } + + return pipe; +} + +int pipe_read(pipe_t* pipe, void* buff, size_t count, int* error){ + + spinlock_acquire(&pipe->lock); + + int readc = 0; + *error = 0; + + for(;;){ + + arch_interrupt_disable(); + + readc = ringbuffer_read(&pipe->buff, buff, count); + + if(readc > 0){ + arch_interrupt_enable(); + event_signal(&pipe->revent, true); + break; + } + + if(pipe->writers == 0) + break; + + spinlock_release(&pipe->lock); + + if(event_wait(&pipe->wevent, true)){ + readc = -1; + *error = EINTR; + break; + } + + spinlock_acquire(&pipe->lock); + + } + + spinlock_release(&pipe->lock); + + return readc; +} + +int pipe_write(pipe_t* pipe, void* buff, size_t count, int* error){ + spinlock_acquire(&pipe->lock); + int writec = 0; + *error = 0; + if(pipe->readers == 0){ + *error = EPIPE; + return -1; + } + + for(;;){ + + arch_interrupt_disable(); + + writec = ringbuffer_write(&pipe->buff, buff, count); + + if(writec > 0){ + event_signal(&pipe->wevent, true); + break; + } + + + spinlock_release(&pipe->lock); + + if(event_wait(&pipe->revent, true)){ + *error = EINTR; + writec = -1; + break; + } + spinlock_acquire(&pipe->lock); + + if(pipe->readers == 0){ + *error = EPIPE; + break; + } + } + + spinlock_release(&pipe->lock); + + return writec; +} diff --git a/src/sys/syscalls/open.c b/src/sys/syscalls/open.c index 48d07a9a..3207fac8 100644 --- a/src/sys/syscalls/open.c +++ b/src/sys/syscalls/open.c @@ -10,7 +10,6 @@ syscallret syscall_open(const char* pathname, int flags, mode_t mode){ - syscallret retv; retv.ret = -1; @@ -96,7 +95,6 @@ syscallret syscall_open(const char* pathname, int flags, mode_t mode){ fd_release(fd); fd_free(&proc->fdtable, fd); - fd->node = NULL; free(name); return retv;