File: [local] / prex / usr / server / fs / fifofs / fifo_vnops.c (download)
Revision 1.1.1.1 (vendor branch), Tue Aug 19 12:47:01 2008 UTC (16 years ago) by nbrk
Branch: MAIN, KOHSUKE
CVS Tags: PREX_0_8_BASE, HEAD Changes since 1.1: +0 -0 lines
Initial import of Prex, Portable Real-time Embedded POSIX microkernel system.
I have totally new directions in my development (more focused on real hardware, not virtual one).
Old hacks are available in prex-old module. They will be carefully re-designed and merged soon.
|
/*
* Copyright (c) 2008, Kohsuke Ohtani
* 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 author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
/*
* fifofs - FIFO/pipe file system.
*/
#include <prex/prex.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/mount.h>
#include <sys/syslog.h>
#include <sys/dirent.h>
#include <sys/list.h>
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <fcntl.h>
#include "fifo.h"
struct fifo_node {
struct list fn_link;
char *fn_name; /* name (null-terminated) */
cond_t fn_rcond; /* cv for read */
cond_t fn_wcond; /* cv for write */
mutex_t fn_rmtx; /* mutex for read */
mutex_t fn_wmtx; /* mutex for write */
int fn_readers; /* reader count */
int fn_writers; /* writer count */
int fn_start; /* start offset of buffer data */
int fn_size; /* siez of buffer data */
char *fn_buf; /* pointer to buffer */
};
#define fifo_mount ((vfsop_mount_t)vfs_nullop)
#define fifo_unmount ((vfsop_umount_t)vfs_nullop)
#define fifo_sync ((vfsop_sync_t)vfs_nullop)
#define fifo_vget ((vfsop_vget_t)vfs_nullop)
#define fifo_statfs ((vfsop_statfs_t)vfs_nullop)
static int fifo_open (vnode_t, int);
static int fifo_close (vnode_t, file_t);
static int fifo_read (vnode_t, file_t, void *, size_t, size_t *);
static int fifo_write (vnode_t, file_t, void *, size_t, size_t *);
#define fifo_seek ((vnop_seek_t)vop_nullop)
static int fifo_ioctl (vnode_t, file_t, u_long, void *);
#define fifo_fsync ((vnop_fsync_t)vop_nullop)
static int fifo_readdir (vnode_t, file_t, struct dirent *);
static int fifo_lookup (vnode_t, char *, vnode_t);
static int fifo_create (vnode_t, char *, mode_t);
static int fifo_remove (vnode_t, vnode_t, char *);
#define fifo_rename ((vnop_rename_t)vop_einval)
#define fifo_mkdir ((vnop_mkdir_t)vop_einval)
#define fifo_rmdir ((vnop_rmdir_t)vop_einval)
#define fifo_getattr ((vnop_getattr_t)vop_nullop)
#define fifo_setattr ((vnop_setattr_t)vop_nullop)
#define fifo_inactive ((vnop_inactive_t)vop_nullop)
#define fifo_truncate ((vnop_truncate_t)vop_nullop)
static void wait_reader(vnode_t);
static void wakeup_reader(vnode_t);
static void wait_writer(vnode_t);
static void wakeup_writer(vnode_t);
#if CONFIG_FS_THREADS > 1
static mutex_t fifo_lock = MUTEX_INITIALIZER;
#endif
static struct list fifo_head;
/*
* vnode operations
*/
struct vnops fifofs_vnops = {
fifo_open, /* open */
fifo_close, /* close */
fifo_read, /* read */
fifo_write, /* write */
fifo_seek, /* seek */
fifo_ioctl, /* ioctl */
fifo_fsync, /* fsync */
fifo_readdir, /* readdir */
fifo_lookup, /* lookup */
fifo_create, /* create */
fifo_remove, /* remove */
fifo_rename, /* remame */
fifo_mkdir, /* mkdir */
fifo_rmdir, /* rmdir */
fifo_getattr, /* getattr */
fifo_setattr, /* setattr */
fifo_inactive, /* inactive */
fifo_truncate, /* truncate */
};
/*
* File system operations
*/
struct vfsops fifofs_vfsops = {
fifo_mount, /* mount */
fifo_unmount, /* unmount */
fifo_sync, /* sync */
fifo_vget, /* vget */
fifo_statfs, /* statfs */
&fifofs_vnops, /* vnops */
};
static int
fifo_open(vnode_t vp, int flags)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("fifo_open: path=%s\n", vp->v_path));
if (!strcmp(vp->v_path, "/")) /* root ? */
return 0;
/*
* Unblock all threads who are waiting in open().
*/
if (flags & FREAD) {
if (np->fn_readers == 0 && np->fn_writers > 0)
wakeup_writer(vp);
np->fn_readers++;
}
if (flags & FWRITE) {
if (np->fn_writers == 0 && np->fn_readers > 0)
wakeup_reader(vp);
np->fn_writers++;
}
/*
* If no-one opens FIFO at the other side, wait for open().
*/
if (flags & FREAD) {
if (flags & O_NONBLOCK) {
} else {
while (np->fn_writers == 0)
wait_writer(vp);
}
}
if (flags & FWRITE) {
if (flags & O_NONBLOCK) {
if (np->fn_readers == 0)
return ENXIO;
} else {
while (np->fn_readers == 0)
wait_reader(vp);
}
}
return 0;
}
static int
fifo_close(vnode_t vp, file_t fp)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("fifo_close: fp=%x\n", fp));
if (np == NULL)
return 0;
if (fp->f_flags & FREAD) {
np->fn_readers--;
if (np->fn_readers == 0)
wakeup_writer(vp);
}
if (fp->f_flags & FWRITE) {
np->fn_writers--;
if (np->fn_writers == 0)
wakeup_reader(vp);
}
if (vp->v_refcnt > 1)
return 0;
return 0;
}
static int
fifo_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
{
struct fifo_node *np = vp->v_data;
char *p = buf;
int pos, nbytes;
DPRINTF(("fifo_read\n"));
/*
* If nothing in the pipe, wait.
*/
while (np->fn_size == 0) {
/*
* No data and no writer, then EOF
*/
if (np->fn_writers == 0) {
*result = 0;
return 0;
}
/*
* wait for data
*/
wait_writer(vp);
}
/*
* Read
*/
nbytes = (np->fn_size < size) ? np->fn_size : size;
np->fn_size -= nbytes;
*result = nbytes;
pos = np->fn_start;
while (nbytes > 0) {
*p++ = np->fn_buf[pos];
if (++pos > PIPE_BUF)
pos = 0;
nbytes--;
}
np->fn_start = pos;
wakeup_writer(vp);
return 0;
}
static int
fifo_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
{
struct fifo_node *np = vp->v_data;
char *p = buf;
int pos, nfree, nbytes;
DPRINTF(("fifo_write\n"));
again:
/*
* If the pipe is full,
* wait for reads to deplete
* and truncate it.
*/
while (np->fn_size >= PIPE_BUF)
wait_reader(vp);
/*
* Write
*/
nfree = PIPE_BUF - np->fn_size;
nbytes = (nfree < size) ? nfree : size;
pos = np->fn_start + np->fn_size;
if (pos >= PIPE_BUF)
pos -= PIPE_BUF;
np->fn_size += nbytes;
size -= nbytes;
while (nbytes > 0) {
np->fn_buf[pos] = *p++;
if (++pos > PIPE_BUF)
pos = 0;
nbytes--;
}
wakeup_reader(vp);
if (size > 0)
goto again;
*result = size;
return 0;
}
static int
fifo_ioctl(vnode_t vp, file_t fp, u_long cmd, void *arg)
{
DPRINTF(("fifo_ioctl\n"));
return EINVAL;
}
static int
fifo_lookup(vnode_t dvp, char *name, vnode_t vp)
{
list_t head, n;
struct fifo_node *np = NULL;
int found;
DPRINTF(("fifo_lookup: %s\n", name));
if (*name == '\0')
return ENOENT;
mutex_lock(&fifo_lock);
found = 0;
head = &fifo_head;
for (n = list_first(head); n != head; n = list_next(n)) {
np = list_entry(n, struct fifo_node, fn_link);
if (strcmp(name, np->fn_name) == 0) {
found = 1;
break;
}
}
if (found == 0) {
mutex_unlock(&fifo_lock);
return ENOENT;
}
vp->v_data = np;
vp->v_mode = ALLPERMS;
vp->v_type = VFIFO;
vp->v_size = 0;
mutex_unlock(&fifo_lock);
return 0;
}
static int
fifo_create(vnode_t dvp, char *name, mode_t mode)
{
struct fifo_node *np;
DPRINTF(("create %s in %s\n", name, dvp->v_path));
#if 0
if (!S_ISFIFO(mode))
return EINVAL;
#endif
if ((np = malloc(sizeof(struct fifo_node))) == NULL)
return ENOMEM;
if ((np->fn_buf = malloc(PIPE_BUF)) == NULL) {
free(np);
return ENOMEM;
}
np->fn_name = malloc(strlen(name) + 1);
if (np->fn_name == NULL) {
free(np->fn_buf);
free(np);
return ENOMEM;
}
strcpy(np->fn_name, name);
mutex_init(&np->fn_rmtx);
mutex_init(&np->fn_wmtx);
cond_init(&np->fn_rcond);
cond_init(&np->fn_wcond);
np->fn_readers = 0;
np->fn_writers = 0;
np->fn_start = 0;
np->fn_size = 0;
mutex_lock(&fifo_lock);
list_insert(&fifo_head, &np->fn_link);
mutex_unlock(&fifo_lock);
return 0;
}
static int
fifo_remove(vnode_t dvp, vnode_t vp, char *name)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("remove %s in %s\n", name, dvp->v_path));
mutex_lock(&fifo_lock);
list_remove(&np->fn_link);
mutex_unlock(&fifo_lock);
free(np->fn_name);
free(np->fn_buf);
free(np);
vp->v_data = NULL;
return 0;
}
/*
* @vp: vnode of the directory.
*/
static int
fifo_readdir(vnode_t vp, file_t fp, struct dirent *dir)
{
struct fifo_node *np;
list_t head, n;
int i;
mutex_lock(&fifo_lock);
if (fp->f_offset == 0) {
dir->d_type = DT_DIR;
strcpy((char *)&dir->d_name, ".");
} else if (fp->f_offset == 1) {
dir->d_type = DT_DIR;
strcpy((char *)&dir->d_name, "..");
} else {
i = 0;
np = NULL;
head = &fifo_head;
for (n = list_first(head); n != head; n = list_next(n)) {
if (i == (fp->f_offset - 2)) {
np = list_entry(n, struct fifo_node, fn_link);
break;
}
}
if (np == NULL) {
mutex_unlock(&fifo_lock);
return ENOENT;
}
dir->d_type = DT_FIFO;
strcpy((char *)&dir->d_name, np->fn_name);
}
dir->d_fileno = fp->f_offset;
dir->d_namlen = strlen(dir->d_name);
fp->f_offset++;
mutex_unlock(&fifo_lock);
return 0;
}
int
fifofs_init(void)
{
list_init(&fifo_head);
return 0;
}
static void
wait_reader(vnode_t vp)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("wait_reader: %x\n", np));
vn_unlock(vp);
mutex_lock(&np->fn_rmtx);
cond_wait(&np->fn_rcond, &np->fn_rmtx);
mutex_unlock(&np->fn_rmtx);
vn_lock(vp);
}
static void
wakeup_writer(vnode_t vp)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("wakeup_writer: %x\n", np));
cond_broadcast(&np->fn_rcond);
}
static void
wait_writer(vnode_t vp)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("wait_writer: %x\n", np));
vn_unlock(vp);
mutex_lock(&np->fn_wmtx);
cond_wait(&np->fn_wcond, &np->fn_wmtx);
mutex_unlock(&np->fn_wmtx);
vn_lock(vp);
}
static void
wakeup_reader(vnode_t vp)
{
struct fifo_node *np = vp->v_data;
DPRINTF(("wakeup_reader: %x\n", np));
cond_broadcast(&np->fn_wcond);
}