Orion
Barry Adding pipes e59e4fe (2 years, 4 months ago)diff --git a/task/signal.h b/task/signal.h new file mode 100644 index 0000000..9811bc6 --- /dev/null +++ b/task/signal.h @@ -0,0 +1,10 @@ +#ifndef KERNEL_TASK_SIGNAL_H +#define KERNEL_TASK_SIGNAL_H + +/* Structure for Signal Handlers namespace */ +typedef struct SigHandlers { + sighandler_t sig_handler[32]; + refcount_t usage; +} SigHandlers; + +#endif diff --git a/task/syscall.c b/task/syscall.c index 30e1a7b..c1587d3 100644 --- a/task/syscall.c +++ b/task/syscall.c @@ -52,6 +52,7 @@ void *syscalls[] = { [SYSCALL_DUP] = dup, [SYSCALL_DUP2] = dup2, [SYSCALL_ISATTY] = isatty, + [SYSCALL_PIPE] = pipe, /* File System */ [SYSCALL_MOUNT] = mount, diff --git a/vfs/ext2fs/block.c b/vfs/ext2fs/block.c index 28cf480..08f2185 100644 --- a/vfs/ext2fs/block.c +++ b/vfs/ext2fs/block.c @@ -23,10 +23,32 @@ ext2_get_data_addr(SuperBlock *super, Ext2Inode *node, uint32_t index) { uint32_t tmp; char block[4096]; + Ext2Super *rsuper = super->data; + /* Blocks per indirect block */ + uint32_t bpib = (1024 << rsuper->blockSize) / sizeof(uint32_t); /* Main blocks */ if (index < 12) return node->directBlock[index]; index -= 12; + + /* Single indirect block */ + if (index < bpib) { + ext2_read_block(super, node->singleBlock, block); + return *((uint32_t *) block + index); + } + index -= bpib; + + /* Double indirect block */ + if (index < bpib*bpib) { + panic("Attempt to read from double indirect block"); + } + index -= bpib*bpib; + + /* Triple indirect block */ + if (index < bpib*bpib*bpib) { + panic("Attempt to read from triple indirect block"); + } + return 0; } diff --git a/vfs/file.c b/vfs/file.c index d3dfdc6..33fd0b7 100644 --- a/vfs/file.c +++ b/vfs/file.c @@ -30,6 +30,8 @@ file_put(File *file) ASSERT(file->usage); if (--file->usage) return; + if (file->ops && file->ops->release) + file->ops->release(file); if (file->inode) inode_put(file->inode); if (file->path) diff --git a/vfs/inode.c b/vfs/inode.c index 34b5c65..50d6200 100644 --- a/vfs/inode.c +++ b/vfs/inode.c @@ -58,6 +58,8 @@ inode_put(Inode *inode) } /* Clean up */ + if (inode->free_extra) + inode->free_extra(inode); if (S_ISDIR(inode->mode)) entry_clean(inode); else diff --git a/vfs/pipe.c b/vfs/pipe.c new file mode 100644 index 0000000..0566597 --- /dev/null +++ b/vfs/pipe.c @@ -0,0 +1,234 @@ +/* + * This file implements the VFS pipe mechanism. It supports both named and + * anonymous pipes (FIFOs and pipes), and uses the same underlying operations + * for both. It uses a ring buffer to implement the reading/writing. + */ + +#include <stdint.h> +#include <stddef.h> +#include <string.h> +#include <errno.h> +#include "vfs.h" +#include "cache.h" +#include "inode.h" +#include "../mem/heap.h" +#include "../mem/paging.h" +#include "../mem/frame.h" +#include "../task/task.h" + +/* Structure for pipe data */ +typedef struct Pipe { + size_t size; + off_t head, tail; + size_t readers, writers; + TaskQueue readQueue, writeQueue; +} Pipe; + +size_t pipe_read(File *file, char *buf, size_t size, off_t offset); +size_t pipe_write(File *file, char *buf, size_t size, off_t offset); +int pipe_release(File *file); + +FileOps pipeWriteFileOps = { + .write = pipe_write, + .release = pipe_release, +}; +FileOps pipeReadFileOps = { + .read = pipe_read, + .release = pipe_release, +}; + +/* Free a Pipe */ +static void +pipe_free_extra(Inode *inode) +{ + Pipe *pipe = inode->extra; + + /* Resume waiting tasks */ + Task *task; + while ((task = pop_from_queue(&pipe->readQueue)) != NULL) { + unblock_task(task); + send_sig(task, SIGPIPE); + } + while ((task = pop_from_queue(&pipe->writeQueue)) != NULL) { + unblock_task(task); + send_sig(task, SIGPIPE); + } +} + +/* Open an anonymous pipe */ +int +pipe(int pipefd[2]) +{ + if (!verify_access(pipefd, sizeof(int) * 2, PROT_WRITE)) + return -EFAULT; + + /* Allocate file descriptors */ + int freefd = 0, i; + for (i = 0; i < NFILES; i++) + freefd += !current->files->fd[i]; + if (freefd < 2) + return -EMFILE; + + /* Create endpoints */ + File *file[2]; + Pipe *pipe = kmalloc(sizeof(Pipe)); + Inode *inode = kmalloc(sizeof(Inode)); + for (i = 0; i < 2; i++) { + file[i] = kmalloc(sizeof(File)); + + /* Install file descriptors */ + for (pipefd[i] = 0; pipefd[i] < NFILES; pipefd[i]++) + if (!current->files->fd[pipefd[i]]) + break; + current->files->fd[pipefd[i]] = file[i]; + + /* Build files */ + file[i]->inode = inode_get(inode); + file[i]->mode = S_IFIFO | 0666; + file[i]->uid = current->uid; + file[i]->gid = current->gid; + file[i]->usage = 1; + } + file[0]->ops = &pipeReadFileOps; + file[1]->ops = &pipeWriteFileOps; + inode->extra = pipe; + pipe->readers = pipe->writers = 1; + page_create(inode, alloc_frames(1), 0); +} + +/* Read from a pipe */ +size_t +pipe_read(File *file, char *buf, size_t size, off_t offset) +{ + offset %= 4096; + + Pipe *pipe = file->inode->extra; + if (!pipe->writers) { + send_sig(current, SIGPIPE); + return 0; + } + + Task *tmp; + Page *page = page_find(file->inode, 0); + acquire(&quickPageLock); + page_t oldPage = quick_page(page->frame); + size_t count = 0, avail, min, minPart; + while (size) { + avail = pipe->size; + if (!avail) { + quick_page(oldPage); + release(&quickPageLock); + + if (!pipe->writers) + goto end; + + while (tmp = pop_from_queue(&pipe->writeQueue)) + unblock_task(tmp); + add_to_queue(&pipe->readQueue, current); + block_task(WAITING_FOR_IO); + + acquire(&quickPageLock); + oldPage = quick_page(page->frame); + } + avail = pipe->size; + min = (size < avail) ? size : avail; + if (pipe->tail + min >= 4096) { + minPart = 4096 - pipe->tail; + memcpy(buf + count, QUICK_PAGE + pipe->tail, minPart); + memcpy(buf + count + minPart, QUICK_PAGE, + min - minPart); + } else { + memcpy(buf + count, QUICK_PAGE + pipe->tail, min); + } + + size -= min; + count += min; + pipe->tail += min; + pipe->tail %= 4096; + pipe->size -= min; + } + + quick_page(oldPage); + release(&quickPageLock); + +end: + while (tmp = pop_from_queue(&pipe->writeQueue)) + unblock_task(tmp); + + return count; +} + +/* Write to a pipe */ +size_t +pipe_write(File *file, char *buf, size_t size, off_t offset) +{ + offset %= 4096; + + Pipe *pipe = file->inode->extra; + if (!pipe->readers) { + send_sig(current, SIGPIPE); + return 0; + } + + Task *tmp; + Page *page = page_find(file->inode, 0); + acquire(&quickPageLock); + page_t oldPage = quick_page(page->frame); + size_t count = 0, space, min, minPart; + while (size) { + space = 4096 - pipe->size; + if (!space) { + quick_page(oldPage); + release(&quickPageLock); + + while (tmp = pop_from_queue(&pipe->readQueue)) + unblock_task(tmp); + add_to_queue(&pipe->writeQueue, current); + block_task(WAITING_FOR_IO); + + acquire(&quickPageLock); + oldPage = quick_page(page->frame); + } + space = 4096 - pipe->size; + min = (size < space) ? size : space; + if (pipe->head + min >= 4096) { + minPart = 4096 - pipe->head; + memcpy(QUICK_PAGE + pipe->head, buf + count, minPart); + memcpy(QUICK_PAGE, buf + count + minPart, + min - minPart); + } else { + memcpy(QUICK_PAGE + pipe->head, buf + count, min); + } + + size -= min; + count += min; + pipe->head += min; + pipe->head %= 4096; + pipe->size += min; + } + + quick_page(oldPage); + release(&quickPageLock); + + while (tmp = pop_from_queue(&pipe->readQueue)) + unblock_task(tmp); + + return count; +} + +int +pipe_release(File *file) +{ + Task *tmp; + Pipe *pipe = file->inode->extra; + TaskQueue *queue = (file->ops == &pipeReadFileOps) + ? &pipe->writeQueue : &pipe->readQueue; + while (tmp = pop_from_queue(queue)) { + unblock_task(tmp); + send_sig(tmp, SIGPIPE); + } + if (queue == &pipe->readQueue) + pipe->writers--; + else + pipe->readers--; +} diff --git a/vfs/tmpfs/file.c b/vfs/tmpfs/file.c index 252c88f..bc320ed 100644 --- a/vfs/tmpfs/file.c +++ b/vfs/tmpfs/file.c @@ -33,7 +33,7 @@ tmpfs_read(File *file, char *buf, size_t size, off_t offset) if (size + offset > file->inode->size) size = file->inode->size - offset; - uint16_t min; + uint16_t min, indent = offset % 4096; size_t count = 0; Page *page; page_t oldPage; @@ -44,11 +44,12 @@ tmpfs_read(File *file, char *buf, size_t size, off_t offset) break; acquire(&quickPageLock); oldPage = quick_page(page->frame); - memcpy(buf + count, QUICK_PAGE, min); + memcpy(buf + count, QUICK_PAGE + indent, min); quick_page(oldPage); release(&quickPageLock); size -= min; count += min; + indent = 0; } return count; } @@ -60,7 +61,7 @@ tmpfs_write(File *file, char *buf, size_t size, off_t offset) if (size + offset > file->inode->size) file->inode->size = size + offset; - uint16_t min; + uint16_t min, indent = offset % 4096; size_t count = 0; Page *page; page_t oldPage; @@ -72,11 +73,12 @@ tmpfs_write(File *file, char *buf, size_t size, off_t offset) offset); acquire(&quickPageLock); oldPage = quick_page(page->frame); - memcpy(QUICK_PAGE, buf + count, min); + memcpy(QUICK_PAGE + indent, buf + count, min); quick_page(oldPage); release(&quickPageLock); size -= min; count += min; + indent = 0; } return count; } diff --git a/vfs/vfs.c b/vfs/vfs.c index 68f4b34..c4784f2 100644 --- a/vfs/vfs.c +++ b/vfs/vfs.c @@ -322,7 +322,7 @@ close(int fd) } /* Read a file */ -size_t +int read(int fd, void *buf, size_t count) { if (!verify_access(buf, count, PROT_WRITE)) @@ -336,11 +336,12 @@ read(int fd, void *buf, size_t count) if (S_ISDIR(file->mode)) return -EISDIR; - return file_read(file, buf, count); + int sz = (int) file_read(file, buf, count); + return sz; } /* Write a file */ -size_t +int write(int fd, void *buf, size_t count) { if (!verify_access(buf, count, PROT_READ)) @@ -354,7 +355,8 @@ write(int fd, void *buf, size_t count) if (S_ISDIR(file->mode)) return -EISDIR; - return file_write(file, buf, count); + int sz = (int) file_write(file, buf, count); + return sz; } /* I/O Control */ @@ -414,12 +416,13 @@ stat(const char *pathname, struct stat *statbuf) if (!inode) return -ENOENT; if (statbuf) { - statbuf->inode = inode->ino; - statbuf->mode = inode->mode; - statbuf->nlink = inode->nlink; - statbuf->uid = inode->uid; - statbuf->gid = inode->gid; - statbuf->size = inode->size; + statbuf->st_dev = inode->dev; + statbuf->st_ino = inode->ino; + statbuf->st_mode = inode->mode; + statbuf->st_nlink = inode->nlink; + statbuf->st_uid = inode->uid; + statbuf->st_gid = inode->gid; + statbuf->st_size = inode->size; } inode_put(inode); return 0; @@ -437,9 +440,15 @@ fstat(int fd, struct stat *statbuf) if (!file) return -EBADF; Inode *inode = file->inode; - statbuf->inode = inode->ino; - statbuf->mode = inode->mode; - statbuf->size = inode->size; + if (statbuf) { + statbuf->st_dev = inode->dev; + statbuf->st_ino = inode->ino; + statbuf->st_mode = inode->mode; + statbuf->st_nlink = inode->nlink; + statbuf->st_uid = inode->uid; + statbuf->st_gid = inode->gid; + statbuf->st_size = inode->size; + } return 0; } diff --git a/vfs/vfs.h b/vfs/vfs.h index ece5679..6997bf3 100644 --- a/vfs/vfs.h +++ b/vfs/vfs.h @@ -68,12 +68,14 @@ struct Inode { Spinlock lock; InodeOps *ops; FileOps *fileOps; + void *extra; + void (*free_extra)(Inode *); SuperBlock *super; union { DirEntry *dirEntries; /* List of Directory Entries */ PageCache *pages; /* List of Pages */ }; - Inode *lnext; /* Next inode in super list */ + Inode *lnext; /* Next inode in super's list */ }; struct InodeOps { int (*create)(Inode *, DirEntry *, mode_t); @@ -163,8 +165,8 @@ Inode *lookup(const char *name, CustodyChain *chain); int open(const char *name, int flags, ...); /* mode_t mode */ int close(int fd); -size_t read(int fd, void *buf, size_t count); -size_t write(int fd, void *buf, size_t count); +int read(int fd, void *buf, size_t count); +int write(int fd, void *buf, size_t count); int ioctl(int fd, unsigned long request, ...); off_t lseek(int fd, off_t offset, int whence); int stat(const char *pathname, struct stat *statbuf); @@ -175,6 +177,7 @@ int mknod(const char *pathname, mode_t mode, dev_t dev); int rename(const char *oldpath, const char *newpath); int dup(int oldfd); int dup2(int oldfd, int newfd); +int pipe(int pipefd[2]); int mount(const char *src, const char *target, const char *type, unsigned long flags, void *data); int chdir(const char *path);