/* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "file_struct.h" #include "file_table.h" #include #include #include #include #include #include #include #include #include #include #include /* Operations */ static int pipe_read(struct file_struct *pipe, unsigned long pos, char *fs_buf, unsigned int count) { int n; if (!count) return 0; if (!verify_area(fs_buf, count, PF_WRITE)) return -EFAULT; pos &= PIPE_BUFFER_SIZE - 1; n = 0; while (!pipe->size) { if (!pipe->write_count) return 0; if (!condition_wait_interruptible(&pipe->condition)) return -ERESTARTSYS; } do { put_fs_byte(pipe->buffer[pos], fs_buf++); pos = (pos + 1) & (PIPE_BUFFER_SIZE - 1); pipe->size--; n++; count--; } while (count && pipe->size); condition_signal_all(&pipe->condition); return n; } static int pipe_write(struct file_struct *pipe, unsigned long pos, const char *fs_buf, unsigned int count) { int n; if (!count) return 0; if (!verify_area(fs_buf, count, PF_READ)) return -EFAULT; pos &= PIPE_BUFFER_SIZE - 1; n = 0; if (!pipe->read_count) { signal_self(SIGPIPE); return -EPIPE; } do { while (pipe->size == PIPE_BUFFER_SIZE) { if (!pipe->read_count) { signal_self(SIGPIPE); return n ? : -EPIPE; } if (!condition_wait_interruptible(&pipe->condition)) if (!n) return -ERESTARTSYS; } do { pipe->buffer[pos] = get_fs_byte(fs_buf++); pos = (pos + 1) & (PIPE_BUFFER_SIZE - 1); pipe->size++; n++; count--; } while (count && pipe->size < PIPE_BUFFER_SIZE); pipe->mtime = get_time(); condition_signal_all(&pipe->condition); } while (count); return n; } static long pipe_seek(const struct file_struct *pipe, unsigned long pos, long offset, int whence) { return -ESPIPE; } static int pipe_stat(const struct file_struct *pipe, struct stat_struct *fs_buf) { struct stat_struct statbuf; if (!verify_area(fs_buf, sizeof (struct stat_struct), PF_WRITE)) return -EFAULT; statbuf.dev = DEV_NONE; statbuf.id = 0; statbuf.type = FT_PIPE; statbuf.rdev = DEV_NONE; statbuf.size = 0; statbuf.mtime = pipe->mtime; memcpy_tofs(fs_buf, &statbuf, sizeof (struct stat_struct)); return 0; } static int pipe_ioctl(const struct file_struct *pipe, int request, void *fs_arg) { return -ENOTTY; } static const struct file_operations_struct pipe_operations = { .read = pipe_read, .write = pipe_write, .seek = pipe_seek, .stat = pipe_stat, .ioctl = pipe_ioctl }; /* Initialisation / destruction */ static int init_pipe(struct file_struct *pipe) { pipe->file_operations = &pipe_operations; pipe->read_count = 0; pipe->write_count = 0; if (!(pipe->buffer = kmalloc(PIPE_BUFFER_SIZE))) return -ENOMEM; pipe->size = 0; pipe->mtime = get_time(); condition_init(&pipe->condition); return 0; } static void destroy_pipe(struct file_struct *pipe) { kfree(pipe->buffer, PIPE_BUFFER_SIZE); } static void free_pipe(struct file_struct *pipe) { destroy_pipe(pipe); free_file(pipe); } /* Fonctions exportees */ /* Alloue un tube. */ int alloc_pipe(struct file_struct **pipe) { int retval; if (!(*pipe = alloc_file())) { retval = -ENOMEM; goto error; } if ((retval = init_pipe(*pipe)) < 0) goto error_free_pipe; return 0; error_free_pipe: free_file(*pipe); error: return retval; } /* Incremente le nombre de references en lecture sur le tube. */ void pipe_hold_read(struct file_struct *pipe) { pipe->read_count++; } /* Incremente le nombre de references en ecriture sur le tube. */ void pipe_hold_write(struct file_struct *pipe) { pipe->write_count++; } /* Decremente le nombre de references en lecture sur le tube. * Le fichier est libere s'il n'est plus reference. */ void pipe_release_read(struct file_struct *pipe) { pipe->read_count--; if (!pipe->read_count && !pipe->write_count) /* liberable ? */ free_pipe(pipe); else condition_signal_all(&pipe->condition); } /* Decremente le nombre de references en ecriture sur le tube. * Le fichier est libere s'il n'est plus reference. */ void pipe_release_write(struct file_struct *pipe) { pipe->write_count--; if (!pipe->read_count && !pipe->write_count) /* liberable ? */ free_pipe(pipe); else condition_signal_all(&pipe->condition); }