Annotation of prex/usr/server/fs/fifofs/fifo_vnops.c, Revision 1.1
1.1 ! nbrk 1: /*
! 2: * Copyright (c) 2008, Kohsuke Ohtani
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. Neither the name of the author nor the names of any co-contributors
! 14: * may be used to endorse or promote products derived from this software
! 15: * without specific prior written permission.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 18: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 19: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 20: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 21: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 22: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 23: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 25: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 26: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 27: * SUCH DAMAGE.
! 28: */
! 29:
! 30: /*
! 31: * fifofs - FIFO/pipe file system.
! 32: */
! 33:
! 34: #include <prex/prex.h>
! 35: #include <sys/stat.h>
! 36: #include <sys/vnode.h>
! 37: #include <sys/file.h>
! 38: #include <sys/mount.h>
! 39: #include <sys/syslog.h>
! 40: #include <sys/dirent.h>
! 41: #include <sys/list.h>
! 42:
! 43: #include <ctype.h>
! 44: #include <unistd.h>
! 45: #include <errno.h>
! 46: #include <string.h>
! 47: #include <stdlib.h>
! 48: #include <limits.h>
! 49: #include <fcntl.h>
! 50:
! 51: #include "fifo.h"
! 52:
! 53: struct fifo_node {
! 54: struct list fn_link;
! 55: char *fn_name; /* name (null-terminated) */
! 56: cond_t fn_rcond; /* cv for read */
! 57: cond_t fn_wcond; /* cv for write */
! 58: mutex_t fn_rmtx; /* mutex for read */
! 59: mutex_t fn_wmtx; /* mutex for write */
! 60: int fn_readers; /* reader count */
! 61: int fn_writers; /* writer count */
! 62: int fn_start; /* start offset of buffer data */
! 63: int fn_size; /* siez of buffer data */
! 64: char *fn_buf; /* pointer to buffer */
! 65: };
! 66:
! 67: #define fifo_mount ((vfsop_mount_t)vfs_nullop)
! 68: #define fifo_unmount ((vfsop_umount_t)vfs_nullop)
! 69: #define fifo_sync ((vfsop_sync_t)vfs_nullop)
! 70: #define fifo_vget ((vfsop_vget_t)vfs_nullop)
! 71: #define fifo_statfs ((vfsop_statfs_t)vfs_nullop)
! 72:
! 73: static int fifo_open (vnode_t, int);
! 74: static int fifo_close (vnode_t, file_t);
! 75: static int fifo_read (vnode_t, file_t, void *, size_t, size_t *);
! 76: static int fifo_write (vnode_t, file_t, void *, size_t, size_t *);
! 77: #define fifo_seek ((vnop_seek_t)vop_nullop)
! 78: static int fifo_ioctl (vnode_t, file_t, u_long, void *);
! 79: #define fifo_fsync ((vnop_fsync_t)vop_nullop)
! 80: static int fifo_readdir (vnode_t, file_t, struct dirent *);
! 81: static int fifo_lookup (vnode_t, char *, vnode_t);
! 82: static int fifo_create (vnode_t, char *, mode_t);
! 83: static int fifo_remove (vnode_t, vnode_t, char *);
! 84: #define fifo_rename ((vnop_rename_t)vop_einval)
! 85: #define fifo_mkdir ((vnop_mkdir_t)vop_einval)
! 86: #define fifo_rmdir ((vnop_rmdir_t)vop_einval)
! 87: #define fifo_getattr ((vnop_getattr_t)vop_nullop)
! 88: #define fifo_setattr ((vnop_setattr_t)vop_nullop)
! 89: #define fifo_inactive ((vnop_inactive_t)vop_nullop)
! 90: #define fifo_truncate ((vnop_truncate_t)vop_nullop)
! 91:
! 92: static void wait_reader(vnode_t);
! 93: static void wakeup_reader(vnode_t);
! 94: static void wait_writer(vnode_t);
! 95: static void wakeup_writer(vnode_t);
! 96:
! 97: #if CONFIG_FS_THREADS > 1
! 98: static mutex_t fifo_lock = MUTEX_INITIALIZER;
! 99: #endif
! 100:
! 101: static struct list fifo_head;
! 102:
! 103: /*
! 104: * vnode operations
! 105: */
! 106: struct vnops fifofs_vnops = {
! 107: fifo_open, /* open */
! 108: fifo_close, /* close */
! 109: fifo_read, /* read */
! 110: fifo_write, /* write */
! 111: fifo_seek, /* seek */
! 112: fifo_ioctl, /* ioctl */
! 113: fifo_fsync, /* fsync */
! 114: fifo_readdir, /* readdir */
! 115: fifo_lookup, /* lookup */
! 116: fifo_create, /* create */
! 117: fifo_remove, /* remove */
! 118: fifo_rename, /* remame */
! 119: fifo_mkdir, /* mkdir */
! 120: fifo_rmdir, /* rmdir */
! 121: fifo_getattr, /* getattr */
! 122: fifo_setattr, /* setattr */
! 123: fifo_inactive, /* inactive */
! 124: fifo_truncate, /* truncate */
! 125: };
! 126:
! 127: /*
! 128: * File system operations
! 129: */
! 130: struct vfsops fifofs_vfsops = {
! 131: fifo_mount, /* mount */
! 132: fifo_unmount, /* unmount */
! 133: fifo_sync, /* sync */
! 134: fifo_vget, /* vget */
! 135: fifo_statfs, /* statfs */
! 136: &fifofs_vnops, /* vnops */
! 137: };
! 138:
! 139: static int
! 140: fifo_open(vnode_t vp, int flags)
! 141: {
! 142: struct fifo_node *np = vp->v_data;
! 143:
! 144: DPRINTF(("fifo_open: path=%s\n", vp->v_path));
! 145:
! 146: if (!strcmp(vp->v_path, "/")) /* root ? */
! 147: return 0;
! 148:
! 149: /*
! 150: * Unblock all threads who are waiting in open().
! 151: */
! 152: if (flags & FREAD) {
! 153: if (np->fn_readers == 0 && np->fn_writers > 0)
! 154: wakeup_writer(vp);
! 155: np->fn_readers++;
! 156: }
! 157: if (flags & FWRITE) {
! 158: if (np->fn_writers == 0 && np->fn_readers > 0)
! 159: wakeup_reader(vp);
! 160: np->fn_writers++;
! 161: }
! 162:
! 163: /*
! 164: * If no-one opens FIFO at the other side, wait for open().
! 165: */
! 166: if (flags & FREAD) {
! 167: if (flags & O_NONBLOCK) {
! 168: } else {
! 169: while (np->fn_writers == 0)
! 170: wait_writer(vp);
! 171: }
! 172: }
! 173: if (flags & FWRITE) {
! 174: if (flags & O_NONBLOCK) {
! 175: if (np->fn_readers == 0)
! 176: return ENXIO;
! 177: } else {
! 178: while (np->fn_readers == 0)
! 179: wait_reader(vp);
! 180: }
! 181: }
! 182: return 0;
! 183: }
! 184:
! 185: static int
! 186: fifo_close(vnode_t vp, file_t fp)
! 187: {
! 188: struct fifo_node *np = vp->v_data;
! 189:
! 190: DPRINTF(("fifo_close: fp=%x\n", fp));
! 191:
! 192: if (np == NULL)
! 193: return 0;
! 194:
! 195: if (fp->f_flags & FREAD) {
! 196: np->fn_readers--;
! 197: if (np->fn_readers == 0)
! 198: wakeup_writer(vp);
! 199: }
! 200: if (fp->f_flags & FWRITE) {
! 201: np->fn_writers--;
! 202: if (np->fn_writers == 0)
! 203: wakeup_reader(vp);
! 204: }
! 205: if (vp->v_refcnt > 1)
! 206: return 0;
! 207:
! 208: return 0;
! 209: }
! 210:
! 211: static int
! 212: fifo_read(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
! 213: {
! 214: struct fifo_node *np = vp->v_data;
! 215: char *p = buf;
! 216: int pos, nbytes;
! 217:
! 218: DPRINTF(("fifo_read\n"));
! 219:
! 220: /*
! 221: * If nothing in the pipe, wait.
! 222: */
! 223: while (np->fn_size == 0) {
! 224: /*
! 225: * No data and no writer, then EOF
! 226: */
! 227: if (np->fn_writers == 0) {
! 228: *result = 0;
! 229: return 0;
! 230: }
! 231: /*
! 232: * wait for data
! 233: */
! 234: wait_writer(vp);
! 235: }
! 236: /*
! 237: * Read
! 238: */
! 239: nbytes = (np->fn_size < size) ? np->fn_size : size;
! 240: np->fn_size -= nbytes;
! 241: *result = nbytes;
! 242: pos = np->fn_start;
! 243: while (nbytes > 0) {
! 244: *p++ = np->fn_buf[pos];
! 245: if (++pos > PIPE_BUF)
! 246: pos = 0;
! 247: nbytes--;
! 248: }
! 249: np->fn_start = pos;
! 250:
! 251: wakeup_writer(vp);
! 252: return 0;
! 253: }
! 254:
! 255: static int
! 256: fifo_write(vnode_t vp, file_t fp, void *buf, size_t size, size_t *result)
! 257: {
! 258: struct fifo_node *np = vp->v_data;
! 259: char *p = buf;
! 260: int pos, nfree, nbytes;
! 261:
! 262: DPRINTF(("fifo_write\n"));
! 263:
! 264: again:
! 265: /*
! 266: * If the pipe is full,
! 267: * wait for reads to deplete
! 268: * and truncate it.
! 269: */
! 270: while (np->fn_size >= PIPE_BUF)
! 271: wait_reader(vp);
! 272:
! 273: /*
! 274: * Write
! 275: */
! 276: nfree = PIPE_BUF - np->fn_size;
! 277: nbytes = (nfree < size) ? nfree : size;
! 278:
! 279: pos = np->fn_start + np->fn_size;
! 280: if (pos >= PIPE_BUF)
! 281: pos -= PIPE_BUF;
! 282: np->fn_size += nbytes;
! 283: size -= nbytes;
! 284: while (nbytes > 0) {
! 285: np->fn_buf[pos] = *p++;
! 286: if (++pos > PIPE_BUF)
! 287: pos = 0;
! 288: nbytes--;
! 289: }
! 290:
! 291: wakeup_reader(vp);
! 292:
! 293: if (size > 0)
! 294: goto again;
! 295:
! 296: *result = size;
! 297: return 0;
! 298: }
! 299:
! 300: static int
! 301: fifo_ioctl(vnode_t vp, file_t fp, u_long cmd, void *arg)
! 302: {
! 303: DPRINTF(("fifo_ioctl\n"));
! 304: return EINVAL;
! 305: }
! 306:
! 307: static int
! 308: fifo_lookup(vnode_t dvp, char *name, vnode_t vp)
! 309: {
! 310: list_t head, n;
! 311: struct fifo_node *np = NULL;
! 312: int found;
! 313:
! 314: DPRINTF(("fifo_lookup: %s\n", name));
! 315:
! 316: if (*name == '\0')
! 317: return ENOENT;
! 318:
! 319: mutex_lock(&fifo_lock);
! 320:
! 321: found = 0;
! 322: head = &fifo_head;
! 323: for (n = list_first(head); n != head; n = list_next(n)) {
! 324: np = list_entry(n, struct fifo_node, fn_link);
! 325: if (strcmp(name, np->fn_name) == 0) {
! 326: found = 1;
! 327: break;
! 328: }
! 329: }
! 330: if (found == 0) {
! 331: mutex_unlock(&fifo_lock);
! 332: return ENOENT;
! 333: }
! 334: vp->v_data = np;
! 335: vp->v_mode = ALLPERMS;
! 336: vp->v_type = VFIFO;
! 337: vp->v_size = 0;
! 338:
! 339: mutex_unlock(&fifo_lock);
! 340: return 0;
! 341: }
! 342:
! 343: static int
! 344: fifo_create(vnode_t dvp, char *name, mode_t mode)
! 345: {
! 346: struct fifo_node *np;
! 347:
! 348: DPRINTF(("create %s in %s\n", name, dvp->v_path));
! 349:
! 350: #if 0
! 351: if (!S_ISFIFO(mode))
! 352: return EINVAL;
! 353: #endif
! 354:
! 355: if ((np = malloc(sizeof(struct fifo_node))) == NULL)
! 356: return ENOMEM;
! 357:
! 358: if ((np->fn_buf = malloc(PIPE_BUF)) == NULL) {
! 359: free(np);
! 360: return ENOMEM;
! 361: }
! 362: np->fn_name = malloc(strlen(name) + 1);
! 363: if (np->fn_name == NULL) {
! 364: free(np->fn_buf);
! 365: free(np);
! 366: return ENOMEM;
! 367: }
! 368:
! 369: strcpy(np->fn_name, name);
! 370: mutex_init(&np->fn_rmtx);
! 371: mutex_init(&np->fn_wmtx);
! 372: cond_init(&np->fn_rcond);
! 373: cond_init(&np->fn_wcond);
! 374: np->fn_readers = 0;
! 375: np->fn_writers = 0;
! 376: np->fn_start = 0;
! 377: np->fn_size = 0;
! 378:
! 379: mutex_lock(&fifo_lock);
! 380: list_insert(&fifo_head, &np->fn_link);
! 381: mutex_unlock(&fifo_lock);
! 382: return 0;
! 383: }
! 384:
! 385: static int
! 386: fifo_remove(vnode_t dvp, vnode_t vp, char *name)
! 387: {
! 388: struct fifo_node *np = vp->v_data;
! 389:
! 390: DPRINTF(("remove %s in %s\n", name, dvp->v_path));
! 391:
! 392: mutex_lock(&fifo_lock);
! 393: list_remove(&np->fn_link);
! 394: mutex_unlock(&fifo_lock);
! 395:
! 396: free(np->fn_name);
! 397: free(np->fn_buf);
! 398: free(np);
! 399:
! 400: vp->v_data = NULL;
! 401: return 0;
! 402: }
! 403:
! 404: /*
! 405: * @vp: vnode of the directory.
! 406: */
! 407: static int
! 408: fifo_readdir(vnode_t vp, file_t fp, struct dirent *dir)
! 409: {
! 410: struct fifo_node *np;
! 411: list_t head, n;
! 412: int i;
! 413:
! 414: mutex_lock(&fifo_lock);
! 415:
! 416: if (fp->f_offset == 0) {
! 417: dir->d_type = DT_DIR;
! 418: strcpy((char *)&dir->d_name, ".");
! 419: } else if (fp->f_offset == 1) {
! 420: dir->d_type = DT_DIR;
! 421: strcpy((char *)&dir->d_name, "..");
! 422: } else {
! 423: i = 0;
! 424: np = NULL;
! 425: head = &fifo_head;
! 426: for (n = list_first(head); n != head; n = list_next(n)) {
! 427: if (i == (fp->f_offset - 2)) {
! 428: np = list_entry(n, struct fifo_node, fn_link);
! 429: break;
! 430: }
! 431: }
! 432: if (np == NULL) {
! 433: mutex_unlock(&fifo_lock);
! 434: return ENOENT;
! 435: }
! 436: dir->d_type = DT_FIFO;
! 437: strcpy((char *)&dir->d_name, np->fn_name);
! 438: }
! 439: dir->d_fileno = fp->f_offset;
! 440: dir->d_namlen = strlen(dir->d_name);
! 441:
! 442: fp->f_offset++;
! 443:
! 444: mutex_unlock(&fifo_lock);
! 445: return 0;
! 446: }
! 447:
! 448: int
! 449: fifofs_init(void)
! 450: {
! 451: list_init(&fifo_head);
! 452: return 0;
! 453: }
! 454:
! 455:
! 456: static void
! 457: wait_reader(vnode_t vp)
! 458: {
! 459: struct fifo_node *np = vp->v_data;
! 460:
! 461: DPRINTF(("wait_reader: %x\n", np));
! 462: vn_unlock(vp);
! 463: mutex_lock(&np->fn_rmtx);
! 464: cond_wait(&np->fn_rcond, &np->fn_rmtx);
! 465: mutex_unlock(&np->fn_rmtx);
! 466: vn_lock(vp);
! 467: }
! 468:
! 469: static void
! 470: wakeup_writer(vnode_t vp)
! 471: {
! 472: struct fifo_node *np = vp->v_data;
! 473:
! 474: DPRINTF(("wakeup_writer: %x\n", np));
! 475: cond_broadcast(&np->fn_rcond);
! 476: }
! 477:
! 478: static void
! 479: wait_writer(vnode_t vp)
! 480: {
! 481: struct fifo_node *np = vp->v_data;
! 482:
! 483: DPRINTF(("wait_writer: %x\n", np));
! 484: vn_unlock(vp);
! 485: mutex_lock(&np->fn_wmtx);
! 486: cond_wait(&np->fn_wcond, &np->fn_wmtx);
! 487: mutex_unlock(&np->fn_wmtx);
! 488: vn_lock(vp);
! 489: }
! 490:
! 491: static void
! 492: wakeup_reader(vnode_t vp)
! 493: {
! 494: struct fifo_node *np = vp->v_data;
! 495:
! 496: DPRINTF(("wakeup_reader: %x\n", np));
! 497: cond_broadcast(&np->fn_wcond);
! 498: }
CVSweb