mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 23:18:21 +00:00
pipes: initial implementation
This commit is contained in:
+25
-4
@@ -3,6 +3,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <kernel/alloc.h>
|
#include <kernel/alloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <kernel/pipe.h>
|
||||||
|
|
||||||
int fd_release(fd_t* fd){
|
int fd_release(fd_t* fd){
|
||||||
spinlock_release(&fd->lock);
|
spinlock_release(&fd->lock);
|
||||||
@@ -99,18 +100,36 @@ int fd_free(fdtable_t* fdtable, int ifd){
|
|||||||
}
|
}
|
||||||
|
|
||||||
fd_t* fd = fdtable->fd[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;
|
fdtable->fd[ifd] = NULL;
|
||||||
spinlock_release(&fd->lock);
|
spinlock_release(&fd->lock);
|
||||||
spinlock_release(&fdtable->lock);
|
spinlock_release(&fdtable->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
spinlock_acquire(&fd->lock);
|
||||||
|
|
||||||
fdtable->fd[ifd] = NULL;
|
fdtable->fd[ifd] = NULL;
|
||||||
|
|
||||||
spinlock_release(&fdtable->lock);
|
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;
|
int err = 0;
|
||||||
if(fd->node)
|
if(fd->node)
|
||||||
err = vfs_close(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];
|
destfd = table->fd[dest];
|
||||||
if(destfd){
|
if(destfd){
|
||||||
spinlock_acquire(&destfd->lock);
|
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);
|
if(destfd->node) vfs_close(destfd->node);
|
||||||
free(destfd);
|
free(destfd);
|
||||||
}
|
}
|
||||||
@@ -244,12 +263,14 @@ int fd_duplicate(fdtable_t* table, int src, int dest, int type, int* ret){
|
|||||||
// everything is set now
|
// everything is set now
|
||||||
|
|
||||||
table->fd[dest] = srcfd;
|
table->fd[dest] = srcfd;
|
||||||
srcfd->refcount++;
|
__atomic_add_fetch(&srcfd->refcount, 1, __ATOMIC_RELAXED);
|
||||||
|
|
||||||
*ret = dest;
|
*ret = dest;
|
||||||
|
|
||||||
fd_release(srcfd);
|
fd_release(srcfd);
|
||||||
spinlock_release(&table->lock);
|
spinlock_release(&table->lock);
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
|
fs_t kerneltmpfs;
|
||||||
|
|
||||||
static int tmpfs_mount(dirnode_t* mountpoint, vnode_t* device, int mountflags, void* fsinfo){
|
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(){
|
fscalls_t* tmpfs_getfuncs(){
|
||||||
|
kerneltmpfs.calls = &funcs;
|
||||||
return &funcs;
|
return &funcs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <kernel/devman.h>
|
#include <kernel/devman.h>
|
||||||
#include <arch/spinlock.h>
|
#include <arch/spinlock.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <kernel/pipe.h>
|
||||||
|
|
||||||
dirnode_t* vfsroot;
|
dirnode_t* vfsroot;
|
||||||
hashtable fsfuncs;
|
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);
|
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){
|
if(type == TYPE_DIR || type == TYPE_LINK){
|
||||||
*error = EINVAL;
|
*error = EINVAL;
|
||||||
return -1;
|
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);
|
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){
|
if(type == TYPE_DIR || type == TYPE_LINK){
|
||||||
*error = EINVAL;
|
*error = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
@@ -136,6 +145,8 @@ int vfs_close(vnode_t* node){
|
|||||||
|
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
|
// TODO free pipe if one
|
||||||
|
|
||||||
if(node->refcount == 0)
|
if(node->refcount == 0)
|
||||||
status = node->fs->calls->close(node);
|
status = node->fs->calls->close(node);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _PIPE_H_INCLUDE
|
||||||
|
#define _PIPE_H_INCLUDE
|
||||||
|
|
||||||
|
#include <ringbuffer.h>
|
||||||
|
#include <kernel/event.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
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
|
||||||
@@ -24,6 +24,7 @@ typedef struct _vnode_t {
|
|||||||
void* fsdata;
|
void* fsdata;
|
||||||
size_t refcount;
|
size_t refcount;
|
||||||
struct _dirnode_t* parent;
|
struct _dirnode_t* parent;
|
||||||
|
void* objdata;
|
||||||
} vnode_t;
|
} vnode_t;
|
||||||
|
|
||||||
// folders are an expansion of vnode_t to save memory
|
// folders are an expansion of vnode_t to save memory
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#include <kernel/pipe.h>
|
||||||
|
#include <kernel/alloc.h>
|
||||||
|
#include <arch/interrupt.h>
|
||||||
|
#include <kernel/event.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <arch/spinlock.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
|
|
||||||
syscallret syscall_open(const char* pathname, int flags, mode_t mode){
|
syscallret syscall_open(const char* pathname, int flags, mode_t mode){
|
||||||
|
|
||||||
syscallret retv;
|
syscallret retv;
|
||||||
retv.ret = -1;
|
retv.ret = -1;
|
||||||
|
|
||||||
@@ -96,7 +95,6 @@ syscallret syscall_open(const char* pathname, int flags, mode_t mode){
|
|||||||
|
|
||||||
fd_release(fd);
|
fd_release(fd);
|
||||||
fd_free(&proc->fdtable, fd);
|
fd_free(&proc->fdtable, fd);
|
||||||
fd->node = NULL;
|
|
||||||
free(name);
|
free(name);
|
||||||
return retv;
|
return retv;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user