📄 fifo_gnodeops.c
字号:
#ifndef lintstatic char *sccsid = "@(#)fifo_gnodeops.c 4.2 (ULTRIX) 2/28/91";#endif lint/************************************************************************ * * * Copyright (c) 1988,89 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * Copyright (c) 1986 by Sun Microsystems, Inc. *//************************************************************************ * Modification History * * 27 Feb 91 -- chet * Fix filesystem timestamping * * 15-Feb-90 -- prs * Added an smp primitive workaround to fifo_rele(). * * 12-Jan-90 -- prs * Modified to use internal ref counters for allocation and * deallocation of fifo structures. * * 24-Jul-89 -- prs * Fixed setjmp case in fifo_open(). * * 04-Jan-89 -- prs * Fixed an ordering bug in fifo_rele that attempted to unlock * a gnode after its memory segment was released. * * 28-Sep-88 -- jaw * add locks to fifo_select * * 14-Sep-88 -- prs * Added fifo_gupdat() and support to update time fields for * fifo gnodes. This change was required by POSIX. * * 06-Sep-88 -- prs * SMP changes to fifo_open(), fifo_close() and fifo_rele(). * * 11-Jul-88 -- prs * Added FIOGETOWN, FIOSETOWN, and FIOASYNC cases to fifo_ioctl(). * Added the routine fifo_wakeup() to send a SIGIO signal, * when ASYNC is enabled on a fifo. Also, added calls to fifo_wakeup * from fifo_close(), when either side of a pipe is shutting down. * * 27-Apr-88 -- prs * Fixed fifo_select code. * * 08-Apr-88 -- prs * Fixed fifo_stat to bzero stat structure if type is GFPIPE. * * 02-Mar-88 -- prs * Fixed fifo_lock and fifo_unlock routines to handle locking * a GFPIPE. * * 10-Feb-88 -- prs * New fifo code. * ************************************************************************/#include "fifonode.h"#include "fifo.h"#include "../net/rpc/types.h"#include "../h/param.h"#include "../h/systm.h"#include "../h/user.h"#include "../h/buf.h"#include "../h/mount.h"#include "../h/kernel.h"#include "../h/gnode_common.h"#include "../h/gnode.h"#include "../h/ioctl.h"#include "../h/proc.h"#include "../h/uio.h"#include "../h/devio.h"#include "../h/conf.h"#include "../h/file.h"#include "../h/stat.h"#include "../h/cmap.h"#include "../h/exec.h"/* SystemV-compatible FIFO implementation */static struct fifo_bufhdr *fifo_bufalloc();static struct fifo_bufhdr *fifo_buffree();struct gnode * spec_namei();int fifo_open();int fifo_close();int fifo_rwgp();int fifo_ioctl();int fifo_select();int spec_access();int spec_link();int spec_unlink();int fifo_lock();int fifo_unlock();int fifo_rele();int spec_inactive();int spec_badop();int spec_rename();int spec_noop();int spec_trunc();int spec_syncgp();int ufs_seek();int fifo_stat();int fifo_gupdat();int spec_getval();struct gnode_ops FIFO_gnode_ops = { spec_namei, /* namei */ spec_link, /* link */ spec_unlink, /* unlink */ 0, /* mkdir */ spec_noop, /* rmdir */ 0, /* maknode */ spec_rename, /* rename */ spec_noop, /* getdirents */ fifo_rele, /* rele */ spec_syncgp, /* syncgp */ 0, /* trunc */ 0, /* getval */ fifo_rwgp, /* read, write */ 0, /* rlock */ ufs_seek, /* seek */ fifo_stat, /* stat */ fifo_lock, /* lock */ fifo_unlock, /* unlock */ fifo_gupdat, /* update */ fifo_open, /* open */ fifo_close, /* close */ fifo_select, /* select */ 0, /* readlink */ 0, /* symlink */ fifo_ioctl, /* fcntl */ 0, /* freegn */ 0 /* bmap */};struct gnode_ops *fifo_gnodeops = &FIFO_gnode_ops;/* * open a fifo -- sleep until there are at least one reader & one writer *//*ARGSUSED*/intfifo_open(gp, flag) struct gnode *gp; int flag;{ register struct fifonode *fp; gfs_lock(gp); if (gp->g_fifo == NULL) { KM_ALLOC(gp->g_fifo, struct fifonode *, sizeof(struct fifonode), KM_TEMP, KM_CLEAR); if (gp->g_fifo == NULL) { printf("fifo_open: Couldn't alloc %d bytes\n", sizeof(struct fifonode)); panic("fifo_open: KM_ALLOC"); } } /* * Setjmp in case open is interrupted. * If it is, close and return error. */ if (setjmp(&u.u_qsave)) { (void) fifo_close(gp, flag & FMASK); return (EINTR); } fp = GTOF(gp); if (flag & FREAD) { if (fp->fn_rcnt++ == 0) /* if any writers waiting, wake them up */ wakeup((caddr_t) &fp->fn_rcnt); } if (flag & FWRITE) { if ((flag & (FNDELAY|FNBLOCK)) && (fp->fn_rcnt == 0)) { gfs_unlock(gp); return (ENXIO); } if (fp->fn_wcnt++ == 0) /* if any readers waiting, wake them up */ wakeup((caddr_t) &fp->fn_wcnt); } if (flag & FREAD) { while (fp->fn_wcnt == 0) { /* if no delay, or data in fifo, open is complete */ if ((flag & (FNDELAY|FNBLOCK)) || fp->fn_size) { gfs_unlock(gp); return (0); } (void) sleep_unlock((caddr_t) &fp->fn_wcnt, PPIPE, &gp->g_lk); gfs_lock(gp); } } if (flag & FWRITE) { while (fp->fn_rcnt == 0) { (void) sleep_unlock((caddr_t) &fp->fn_rcnt, PPIPE, &gp->g_lk); gfs_lock(gp); } } gfs_unlock(gp); return (0);}/* * close a fifo * On final close, all buffered data goes away *//*ARGSUSED*/intfifo_close(gp, flag) struct gnode *gp; int flag;{ register struct fifonode *fp; register struct fifo_bufhdr *bp; register struct ucred *cred = u.u_cred; gfs_lock(gp); fp = GTOF(gp); if (flag & FREAD) { if (--fp->fn_rcnt == 0) { if (fp->fn_flag & IFIW) { fp->fn_flag &= ~IFIW; wakeup((caddr_t) &fp->fn_wcnt); } if (fp->fn_wselp) { selwakeup(fp->fn_wselp, fp->fn_flag & IF_WCOLL); fp->fn_flag &= ~IF_WCOLL; fp->fn_wselp = 0; } if ((fp->fn_flag & IF_RASYNC) || (fp->fn_flag & IF_WASYNC)) { fifo_wakeup(fp); fp->fn_flag &= ~IF_RASYNC; fp->fn_rpgrp = 0; } } } if (flag & FWRITE) { if (--fp->fn_wcnt == 0) { if (fp->fn_flag & IFIR) { fp->fn_flag &= ~IFIR; wakeup((caddr_t) &fp->fn_rcnt); } if (fp->fn_rselp) { selwakeup(fp->fn_rselp, fp->fn_flag & IF_RCOLL); fp->fn_flag &= ~IF_RCOLL; fp->fn_rselp = 0; } if ((fp->fn_flag & IF_RASYNC) || (fp->fn_flag & IF_WASYNC)) { fifo_wakeup(fp); fp->fn_flag &= ~IF_WASYNC; fp->fn_wpgrp = 0; } } } if ((fp->fn_rcnt == 0) && (fp->fn_wcnt == 0)) { /* free all buffers associated with this fifo */ for (bp = fp->fn_buf; bp != NULL; ) { bp = fifo_buffree(bp, fp); } /* update times only if there were bytes flushed from fifo */ if (fp->fn_size != 0) { gp->g_size = 0; gp->g_flag |= GUPD|GCHG; (void) fifo_gupdat(gp, timepick, timepick, 0, cred); } /* free fifo structure */ kmem_free((caddr_t)GTOF(gp), KM_TEMP); gp->g_fifo = NULL; } gfs_unlock(gp); return (0);}/* * read/write a fifo *//*ARGSUSED*/intfifo_rwgp(gp, uiop, rw, ioflag, cred) struct gnode *gp; struct uio *uiop; enum uio_rw rw; int ioflag; struct ucred *cred;{ register struct fifonode *fp; register struct fifo_bufhdr *bp; register u_int count; register int off; register unsigned i; register int rval = 0; int first_pass = 1;#ifdef SANITY if ((ioflag & IO_APPEND) == 0) printf("fifo_rdwr: no append flag\n"); if (uiop->uio_offset != 0) printf("fifo_rdwr: non-zero offset: %d\n", uiop->uio_offset);#endif SANITY fp = GTOF(gp); gfs_lock(gp); if (rw == UIO_WRITE) { /* UIO_WRITE */ /* * PIPE_BUF: max number of bytes buffered per open pipe * PIPE_MAX: max size of single write to a pipe * * If the count is less than PIPE_BUF, it must occur * atomically. If it does not currently fit in the * kernel pipe buffer, either sleep or return 0 bytes * written, depending on FNDELAY (*** EAGAIN? ***). * * If the count is greater than PIPE_BUF, it will be * non-atomic (FNDELAY clear). If FNDELAY is set, * write as much as will fit into the kernel pipe buffer * and return the number of bytes written. * * If the count is greater than PIPE_MAX, return EINVAL. */ if ((unsigned)uiop->uio_resid > PIPE_MAX) { rval = EINVAL; goto rdwrdone; } while (count = uiop->uio_resid) { if (fp->fn_rcnt == 0) { /* no readers anymore! */ psignal(u.u_procp, SIGPIPE); rval = EPIPE; goto rdwrdone; } if ((count + fp->fn_size) > PIPE_BUF) { if (ioflag & (FNDELAY|FNBLOCK)) { /* NO DELAY */ if (count <= PIPE_BUF) { /* * Write will be satisfied * atomically. * Scholars Differ :: * P1003 may require EAGAIN */ if (first_pass) if (u.u_procp->p_progenv == A_POSIX) rval = EAGAIN; else rval = EWOULDBLOCK; goto rdwrdone; } else if (fp->fn_size >= PIPE_BUF) { /* * Write will never be atomic. * At this point, it cannot even be * partial. However, some portion * of the write may already have * succeeded. If so, uio_resid * reflects this. If not, we will * have to keep track of this fact * in order to return EAGAIN. */ if (first_pass) if (u.u_procp->p_progenv == A_POSIX) rval = EAGAIN; else rval = EWOULDBLOCK; goto rdwrdone; } } else { /* DELAY */ if ( (count <= PIPE_BUF) || (fp->fn_size >= PIPE_BUF) ) { /* * Sleep until there is room for this request. * On wakeup, go back to the top of the loop. */ fp->fn_flag |= IFIW; (void) sleep_unlock((caddr_t) &fp->fn_wcnt, PPIPE, &gp->g_lk); gfs_lock(gp); goto wrloop; } } /* at this point, can do a partial write */ count = PIPE_BUF - fp->fn_size; } /* * Can write 'count' bytes to pipe now. Make sure * there is enough space in the allocated buffer list. * If not, try to allocate more. * If allocation does not succeed immediately, go back * to the top of the loop to make sure everything is * still cool. */#ifdef SANITY if ((fp->fn_wptr - fp->fn_rptr) != fp->fn_size) printf("fifo_write: ptr mismatch...size:%d wptr:%d rptr:%d\n", fp->fn_size, fp->fn_wptr, fp->fn_rptr); if (fp->fn_rptr > PIPE_BSZ) printf("fifo_write: rptr too big...rptr:%d\n", fp->fn_rptr); if (fp->fn_wptr > (fp->fn_nbuf * PIPE_BSZ)) printf("fifo_write: wptr too big...wptr:%d nbuf:%d\n", fp->fn_wptr, fp->fn_nbuf);#endif SANITY while (((fp->fn_nbuf * PIPE_BSZ) - fp->fn_wptr) < count) { if ((bp = fifo_bufalloc(gp, fp)) == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -