diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2004-02-24 03:56:07 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2004-02-24 03:56:07 +0000 |
commit | b897eb2158e1fffb5f71d142ac086f0dfa725fca (patch) | |
tree | 8cd75e686b1307fee8971ec7eb305af08ddefcce /sys/miscfs | |
parent | fbff7ee7ee20b56406603fb14c7c7a2bb3ce5f91 (diff) |
FIFO fixes adapted from FreeBSD:
o use different wchan string for reading and writing
o make O_RDWR not block forever
o remove some useless casts
o reorganize the normal, blocking code path (ie: O_NONBLOCK not set)
o fix select/poll semantics wrt EOF.
With these changes we pass the FIFO regress. OK tedu@
Diffstat (limited to 'sys/miscfs')
-rw-r--r-- | sys/miscfs/fifofs/fifo_vnops.c | 109 |
1 files changed, 53 insertions, 56 deletions
diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c index 0fecb45b806..74e9eb51a64 100644 --- a/sys/miscfs/fifofs/fifo_vnops.c +++ b/sys/miscfs/fifofs/fifo_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fifo_vnops.c,v 1.17 2004/01/28 23:53:57 millert Exp $ */ +/* $OpenBSD: fifo_vnops.c,v 1.18 2004/02/24 03:56:06 millert Exp $ */ /* $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */ /* @@ -162,7 +162,6 @@ fifo_open(v) struct proc *p = ap->a_p; struct socket *rso, *wso; int error; - static char openstr[] = "fifo"; if ((fip = vp->v_fifoinfo) == NULL) { MALLOC(fip, struct fifoinfo *, sizeof(*fip), M_VNODE, M_WAITOK); @@ -188,49 +187,43 @@ fifo_open(v) return (error); } fip->fi_readers = fip->fi_writers = 0; - wso->so_state |= SS_CANTRCVMORE; - rso->so_state |= SS_CANTSENDMORE; + wso->so_snd.sb_lowat = PIPE_BUF; + rso->so_state |= SS_CANTRCVMORE; } if (ap->a_mode & FREAD) { if (fip->fi_readers++ == 0) { fip->fi_writesock->so_state &= ~SS_CANTSENDMORE; if (fip->fi_writers > 0) - wakeup((caddr_t)&fip->fi_writers); + wakeup(&fip->fi_writers); + } + } + if (ap->a_mode & FWRITE) { + if ((ap->a_mode & O_NONBLOCK) && fip->fi_readers == 0) { + error = ENXIO; + goto bad; } - } else if (ap->a_mode & FWRITE) { if (fip->fi_writers++ == 0) { fip->fi_readsock->so_state &= ~SS_CANTRCVMORE; if (fip->fi_readers > 0) - wakeup((caddr_t)&fip->fi_readers); + wakeup(&fip->fi_readers); } } - if (ap->a_mode & FREAD) { - if (ap->a_mode & O_NONBLOCK) { - } else { - while (fip->fi_writers == 0) { - VOP_UNLOCK(vp, 0, p); - error = tsleep((caddr_t)&fip->fi_readers, - PCATCH | PSOCK, openstr, 0); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (error) - goto bad; - } + if ((ap->a_mode & O_NONBLOCK) == 0) { + if ((ap->a_mode & FREAD) && fip->fi_writers == 0) { + VOP_UNLOCK(vp, 0, p); + error = tsleep(&fip->fi_readers, + PCATCH | PSOCK, "fifor", 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) + goto bad; } - } else if (ap->a_mode & FWRITE) { - if (ap->a_mode & O_NONBLOCK) { - if (fip->fi_readers == 0) { - error = ENXIO; + if ((ap->a_mode & FWRITE) && fip->fi_readers == 0) { + VOP_UNLOCK(vp, 0, p); + error = tsleep(&fip->fi_writers, + PCATCH | PSOCK, "fifow", 0); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); + if (error) goto bad; - } - } else { - while (fip->fi_readers == 0) { - VOP_UNLOCK(vp, 0, p); - error = tsleep((caddr_t)&fip->fi_writers, - PCATCH | PSOCK, openstr, 0); - vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); - if (error) - goto bad; - } } } return (0); @@ -256,7 +249,7 @@ fifo_read(v) register struct uio *uio = ap->a_uio; register struct socket *rso = ap->a_vp->v_fifoinfo->fi_readsock; struct proc *p = uio->uio_procp; - int error, startresid; + int error; #ifdef DIAGNOSTIC if (uio->uio_rw != UIO_READ) @@ -266,21 +259,15 @@ fifo_read(v) return (0); if (ap->a_ioflag & IO_NDELAY) rso->so_state |= SS_NBIO; - startresid = uio->uio_resid; VOP_UNLOCK(ap->a_vp, 0, p); - error = soreceive(rso, (struct mbuf **)0, uio, (struct mbuf **)0, - (struct mbuf **)0, (int *)0); + error = soreceive(rso, NULL, uio, NULL, NULL, NULL); vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); - /* - * Clear EOF indication after first such return. - */ - if (uio->uio_resid == startresid) - rso->so_state &= ~SS_CANTRCVMORE; - if (ap->a_ioflag & IO_NDELAY) + if (ap->a_ioflag & IO_NDELAY) { rso->so_state &= ~SS_NBIO; - if ((ap->a_ioflag & IO_NDELAY) && error == EWOULDBLOCK && - ap->a_vp->v_fifoinfo->fi_writers == 0) - error = 0; + if (error == EWOULDBLOCK && + ap->a_vp->v_fifoinfo->fi_writers == 0) + error = 0; + } return (error); } @@ -309,7 +296,7 @@ fifo_write(v) if (ap->a_ioflag & IO_NDELAY) wso->so_state |= SS_NBIO; VOP_UNLOCK(ap->a_vp, 0, p); - error = sosend(wso, (struct mbuf *)0, ap->a_uio, 0, (struct mbuf *)0, 0); + error = sosend(wso, NULL, ap->a_uio, NULL, NULL, 0); vn_lock(ap->a_vp, LK_EXCLUSIVE | LK_RETRY, p); if (ap->a_ioflag & IO_NDELAY) wso->so_state &= ~SS_NBIO; @@ -363,12 +350,24 @@ fifo_poll(v) struct proc *a_p; } */ *ap = v; struct file filetmp; + short ostate; int revents = 0; if (ap->a_events & (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND)) { + /* + * Socket and FIFO poll(2) semantics differ wrt EOF on read. + * Unlike a normal socket, FIFOs don't care whether or not + * SS_CANTRCVMORE is set. To get the correct semantics we + * must clear SS_CANTRCVMORE from so_state temporarily. + */ + ostate = ap->a_vp->v_fifoinfo->fi_readsock->so_state; + if (ap->a_events & (POLLIN | POLLRDNORM)) + ap->a_vp->v_fifoinfo->fi_readsock->so_state &= + ~SS_CANTRCVMORE; filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_readsock; if (filetmp.f_data) revents |= soo_poll(&filetmp, ap->a_events, ap->a_p); + ap->a_vp->v_fifoinfo->fi_readsock->so_state = ostate; } if (ap->a_events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { filetmp.f_data = (caddr_t)ap->a_vp->v_fifoinfo->fi_writesock; @@ -429,7 +428,7 @@ fifo_close(v) } */ *ap = v; register struct vnode *vp = ap->a_vp; register struct fifoinfo *fip = vp->v_fifoinfo; - int error1, error2; + int error1 = 0, error2 = 0; if (ap->a_fflag & FREAD) { if (--fip->fi_readers == 0) @@ -439,15 +438,13 @@ fifo_close(v) if (--fip->fi_writers == 0) socantrcvmore(fip->fi_readsock); } - if (fip->fi_readers != 0 || fip->fi_writers != 0) - return (0); - error1 = soclose(fip->fi_readsock); - error2 = soclose(fip->fi_writesock); - FREE(fip, M_VNODE); - vp->v_fifoinfo = NULL; - if (error1) - return (error1); - return (error2); + if (fip->fi_readers == 0 && fip->fi_writers == 0) { + error1 = soclose(fip->fi_readsock); + error2 = soclose(fip->fi_writesock); + FREE(fip, M_VNODE); + vp->v_fifoinfo = NULL; + } + return (error1 ? error1 : error2); } /* |