[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH] lib/vfscore: Add anonymous pipe
Adds pipe function that creates an anonymous pipe and creates functions that write and read to a pipe file descriptor. Signed-off-by: Bogdan Lascu <lascu.bogdan96@xxxxxxxxx> --- lib/vfscore/Makefile.uk | 1 + lib/vfscore/exportsyms.uk | 1 + lib/vfscore/include/vfscore/pipe.h | 67 ++++++ lib/vfscore/pipe.c | 409 +++++++++++++++++++++++++++++++++++++ 4 files changed, 478 insertions(+) create mode 100644 lib/vfscore/include/vfscore/pipe.h create mode 100644 lib/vfscore/pipe.c diff --git a/lib/vfscore/Makefile.uk b/lib/vfscore/Makefile.uk index 0166e612..4e519367 100644 --- a/lib/vfscore/Makefile.uk +++ b/lib/vfscore/Makefile.uk @@ -14,6 +14,7 @@ LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/task.c LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/lookup.c LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/fops.c LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/subr_uio.c +LIBVFSCORE_SRCS-y += $(LIBVFSCORE_BASE)/pipe.c EXTRA_LD_SCRIPT-$(CONFIG_LIBVFSCORE) += $(LIBVFSCORE_BASE)/extra.ld diff --git a/lib/vfscore/exportsyms.uk b/lib/vfscore/exportsyms.uk index da7fbaea..16a0f86a 100644 --- a/lib/vfscore/exportsyms.uk +++ b/lib/vfscore/exportsyms.uk @@ -57,6 +57,7 @@ writev truncate mknod preadv +pipe ioctl fdatasync fdopendir diff --git a/lib/vfscore/include/vfscore/pipe.h b/lib/vfscore/include/vfscore/pipe.h new file mode 100644 index 00000000..0c25f4ed --- /dev/null +++ b/lib/vfscore/include/vfscore/pipe.h @@ -0,0 +1,67 @@ +/* pipe.h - pipe header + * + * Authors: Bogdan-George Lascu <lascu.bogdan96@xxxxxxxxx> + * + * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ +#include <vfscore/file.h> +#include <uk/wait.h> +#include <uk/mutex.h> + +#define PIPE_MAX_SIZE (1 << 16) + + +struct pipe_buf { + char *data; + unsigned int max_size; + size_t len; /* Total len of buffer. */ + unsigned int r_off; + unsigned int w_off; +}; + +struct pipe_info { + struct pipe_buf *buf; + int w_count; + int r_count; + int flags; + struct uk_mutex pipe_lock; + struct uk_waitq wq; +}; + +struct pipe_buf *alloc_pipe_buf(int size); +struct pipe_info *alloc_pipe_info(int size, int flags); + +void free_pipe_buf(struct pipe_buf *pipe_buf); +void free_pipe_info(struct pipe_info *pipe_info); + + +#define PIPE_LOCK(__pipe) uk_mutex_lock(&__pipe->pipe_lock) +#define PIPE_UNLOCK(__pipe) uk_mutex_unlock(&__pipe->pipe_lock) + diff --git a/lib/vfscore/pipe.c b/lib/vfscore/pipe.c new file mode 100644 index 00000000..15137627 --- /dev/null +++ b/lib/vfscore/pipe.c @@ -0,0 +1,409 @@ +/* pipe.c - pipe implementation + * + * Authors: Bogdan-George Lascu <lascu.bogdan96@xxxxxxxxx> + * + * Copyright (c) 2019, University Politehnica of Bucharest. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY. + */ + +#include <stdio.h> +#include <string.h> +#include <vfscore/pipe.h> +#include <vfscore/file.h> +#include <vfscore/vnode.h> +#include <vfscore/fs.h> +#include <uk/wait.h> +#include <sys/ioctl.h> + + +size_t get_pipe_buf_free_space(struct pipe_buf *pipe_buf) +{ + return pipe_buf->max_size - pipe_buf->len; +} + +int pipe_can_read(struct pipe_buf *pipe_buf) +{ + return pipe_buf->len > 0; +} + +/* Write blocks until there is enough space to write the entire user buffer. */ +int pipe_can_write(struct pipe_buf *pipe_buf, size_t user_buf_len) +{ + return get_pipe_buf_free_space(pipe_buf) >= user_buf_len; +} + + +static int pipe_write(struct vnode *vnode, + struct uio *buf, int ioflag __unused) +{ + struct pipe_info *pipe = vnode->v_data; + struct pipe_buf *pipe_buf = pipe->buf; + struct iovec iovec; + int to_write = 0; + int i; + + if (!pipe->r_count) { + // TODO before returning the error, send a SIGPIPE signal. + return -EPIPE; + } + + for (i = 0; i < buf->uio_iovcnt; i++) + to_write += buf->uio_iov[i].iov_len; + + uk_waitq_wait_event(&pipe->wq, pipe_can_write(pipe_buf, to_write)); + PIPE_LOCK(pipe); + for (i = 0; i < buf->uio_iovcnt; i++) { + iovec = buf->uio_iov[i]; + + /* Copy the user buffer in pipe buffer. */ + if (pipe_buf->w_off + iovec.iov_len <= pipe_buf->max_size) { + memcpy(pipe_buf->data + pipe_buf->w_off, + iovec.iov_base, + iovec.iov_len); + } else { + int first_copy_bytes; + int second_copy_bytes; + + /* Copy the from current offset to the end. */ + first_copy_bytes = pipe_buf->max_size - pipe_buf->w_off; + memcpy(pipe_buf->data + pipe_buf->w_off, + iovec.iov_base, + first_copy_bytes); + + /* Copy from the begging the remaining bytes. */ + second_copy_bytes = pipe_buf->w_off + + iovec.iov_len + - pipe_buf->max_size; + + memcpy(pipe_buf->data, + iovec.iov_base + first_copy_bytes, + second_copy_bytes); + + } + + /* Update buffer write offset. */ + pipe_buf->w_off = (pipe_buf->w_off + iovec.iov_len) + % pipe_buf->max_size; + + /* Update pipe buf len. */ + pipe_buf->len += iovec.iov_len; + + /* Update bytes written. */ + buf->uio_resid -= iovec.iov_len; + } + PIPE_UNLOCK(pipe); + uk_waitq_wake_up(&pipe->wq); + + return 0; +} + +static int pipe_read(struct vnode *vnode, + struct vfscore_file *vfscore_file __unused, + struct uio *buf, int ioflag __unused) +{ + struct pipe_info *pipe = vnode->v_data; + struct pipe_buf *pipe_buf = pipe->buf; + struct iovec iovec; + int to_read; + int i; + + if ((vfscore_file->f_flags & O_NONBLOCK) && pipe_buf->len == 0) + return -EAGAIN; + + uk_waitq_wait_event(&pipe->wq, pipe_can_read(pipe_buf)); + PIPE_LOCK(pipe); + for (i = 0; i < buf->uio_iovcnt; i++) { + iovec = buf->uio_iov[i]; + to_read = MIN(iovec.iov_len, pipe_buf->len); + if (to_read == 0) + break; + + /* Copy from pipe buffer to user buffer. */ + if (pipe_buf->r_off + to_read <= pipe_buf->max_size) { + memcpy(iovec.iov_base, + pipe_buf->data + pipe_buf->r_off, + to_read); + } else { + int first_copy_bytes; + int second_copy_bytes; + + /* Copy the from current offset to the end. */ + first_copy_bytes = pipe_buf->max_size - pipe_buf->r_off; + memcpy(iovec.iov_base, + pipe_buf->data + pipe_buf->r_off, + first_copy_bytes); + + /* Copy from the begging the remaining bytes. */ + second_copy_bytes = pipe_buf->r_off + + to_read + - pipe_buf->max_size; + + memcpy(iovec.iov_base + first_copy_bytes, + pipe_buf->data, + second_copy_bytes); + + } + + /* Update read buffer offset. */ + pipe_buf->r_off = (pipe_buf->r_off + to_read) % pipe_buf->max_size; + + /* Update pipe buffer len. */ + pipe_buf->len -= to_read; + + /* Update bytes read which will be returned. */ + buf->uio_resid -= to_read; + } + PIPE_UNLOCK(pipe); + uk_waitq_wake_up(&pipe->wq); + + return 0; +} + +static int pipe_close(struct vnode *vnode, + struct vfscore_file *file) +{ + struct pipe_info *pipe = vnode->v_data; + + PIPE_LOCK(pipe); + + if (file->f_flags & UK_FREAD) + pipe->r_count--; + + if (file->f_flags & UK_FWRITE) + pipe->w_count--; + + if (!pipe->r_count && !pipe->w_count) + free_pipe_info(pipe); + + PIPE_UNLOCK(pipe); + + return 0; +} + +static int pipe_seek(struct vnode *vnode __unused, + struct vfscore_file *file __unused, + off_t off1 __unused, off_t off2 __unused) +{ + return -EPIPE; +} + +static int pipe_ioctl(struct vnode *vnode, struct vfscore_file *file __unused, + unsigned long com, void *data __unused) +{ + struct pipe_info *pipe = vnode->v_data; + struct pipe_buf *pipe_buf __unused = pipe->buf; + + switch (com) { +#ifdef FIONREAD + case FIONREAD: + PIPE_LOCK(pipe); + *(int *)data = pipe_buf->len; + PIPE_UNLOCK(pipe); + return 0; +#endif + default: + return -EINVAL; + } +} + +static struct vnops pipe_fops = { + .vop_read = pipe_read, + .vop_write = pipe_write, + .vop_close = pipe_close, + .vop_seek = pipe_seek, + .vop_ioctl = pipe_ioctl, +}; + +struct pipe_buf *alloc_pipe_buf(int max_size) +{ + struct pipe_buf *pipe_buf; + + pipe_buf = uk_calloc(uk_alloc_get_default(), 1, sizeof(*pipe_buf)); + if (!pipe_buf) + return NULL; + pipe_buf->data = uk_calloc(uk_alloc_get_default(), 1, + max_size * sizeof(char)); + if (!pipe_buf->data) { + uk_free(uk_alloc_get_default(), pipe_buf); + return NULL; + } + + pipe_buf->r_off = 0; + pipe_buf->w_off = 0; + pipe_buf->max_size = max_size; + pipe_buf->len = 0; + + return pipe_buf; +} + +struct pipe_info *alloc_pipe_info(int size, int flags) +{ + struct pipe_info *pipe_info; + + pipe_info = uk_calloc(uk_alloc_get_default(), 1, sizeof(*pipe_info)); + if (!pipe_info) + return NULL; + + pipe_info->r_count = 1; + pipe_info->w_count = 1; + pipe_info->flags = flags; + + pipe_info->buf = alloc_pipe_buf(size); + if (!pipe_info->buf) { + uk_free(uk_alloc_get_default(), pipe_info); + return NULL; + } + + uk_mutex_init(&pipe_info->pipe_lock); + uk_waitq_init(&pipe_info->wq); + + return pipe_info; +} + +void free_pipe_buf(struct pipe_buf *pipe_buf) +{ + uk_free(uk_alloc_get_default(), pipe_buf->data); + uk_free(uk_alloc_get_default(), pipe_buf); +} +void free_pipe_info(struct pipe_info *pipe_info) +{ + free_pipe_buf(pipe_info->buf); + uk_free(uk_alloc_get_default(), pipe_info); +} + + +int pipe(int pipefd[2]) +{ + int ret = 0; + int w_fd, r_fd; + struct dentry *w_dentry, *r_dentry; + struct vnode *r_vnode, *w_vnode; + struct vfscore_file *r_file, *w_file; + struct pipe_info *pipe_info; + + /* Reserve file descriptor number. */ + r_fd = vfscore_alloc_fd(); + w_fd = vfscore_alloc_fd(); + if (r_fd < 0 || w_fd < 0) { + ret = -ENFILE; + goto ERR_EXIT; + } + + /* Allocate file, dentry, and vnode. */ + r_file = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_file)); + w_file = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_file)); + if (!r_file || !w_file) { + ret = -ENOMEM; + goto ERR_MALLOC_FILE; + } + + r_dentry = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_dentry)); + w_dentry = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_dentry)); + if (!r_dentry || !w_dentry) { + ret = -ENOMEM; + goto ERR_MALLOC_DENTRY; + } + + r_vnode = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_vnode)); + w_vnode = uk_calloc(uk_alloc_get_default(), 1, sizeof(*r_vnode)); + if (!r_vnode || !w_vnode) { + ret = -ENOMEM; + goto ERR_MALLOC_VNODE; + } + + /* Allocate pipe internal structure. */ + pipe_info = alloc_pipe_info(PIPE_MAX_SIZE, 0); + if (!pipe_info) { + ret = -ENOMEM; + goto ERR_ALLOC_PIPE_INFO; + } + + /* Fill out necessary fields. */ + r_file->fd = r_fd; + w_file->fd = r_fd; + + r_file->f_count = 1; + w_file->f_count = 1; + + r_file->f_flags = UK_FREAD; + w_file->f_flags = UK_FWRITE; + + r_file->f_dentry = r_dentry; + w_file->f_dentry = w_dentry; + + r_dentry->d_vnode = r_vnode; + w_dentry->d_vnode = w_vnode; + + + r_vnode->v_op = &pipe_fops; + w_vnode->v_op = &pipe_fops; + + uk_mutex_init(&r_vnode->v_lock); + uk_mutex_init(&w_vnode->v_lock); + + r_vnode->v_refcnt = 1; + w_vnode->v_refcnt = 1; + + r_vnode->v_data = pipe_info; + w_vnode->v_data = pipe_info; + + /* Assign the file descriptors to the corresponding vfs_file. */ + ret = vfscore_install_fd(r_fd, r_file); + if (ret) + goto ERR_VFS_INSTALL; + + ret = vfscore_install_fd(w_fd, w_file); + if (ret) + goto ERR_VFS_INSTALL; + + /* Fill pipefd fields. */ + pipefd[0] = r_fd; + pipefd[1] = w_fd; + + return ret; + +ERR_VFS_INSTALL: + free_pipe_info(pipe_info); +ERR_ALLOC_PIPE_INFO: + uk_free(uk_alloc_get_default(), r_vnode); + uk_free(uk_alloc_get_default(), w_vnode); +ERR_MALLOC_VNODE: + uk_free(uk_alloc_get_default(), r_dentry); + uk_free(uk_alloc_get_default(), w_dentry); +ERR_MALLOC_DENTRY: + uk_free(uk_alloc_get_default(), r_file); + uk_free(uk_alloc_get_default(), w_file); +ERR_MALLOC_FILE: + vfscore_put_fd(r_fd); + vfscore_put_fd(w_fd); +ERR_EXIT: + UK_ASSERT(ret < 0); + return ret; +} + -- 2.11.0 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |