summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormillert <millert@openbsd.org>2014-10-09 16:36:36 +0000
committermillert <millert@openbsd.org>2014-10-09 16:36:36 +0000
commit25ff029fde333a8ef7edbddb068057e2ce24d571 (patch)
tree915b93d2551f9f4557a22dacace15918b1c36cd3
parentparse and render "from" and "to" clauses in eqn, and render matrices; (diff)
downloadwireguard-openbsd-25ff029fde333a8ef7edbddb068057e2ce24d571.tar.xz
wireguard-openbsd-25ff029fde333a8ef7edbddb068057e2ce24d571.zip
Instead of trying to emulate select/poll semantics with respect to EOF
by mutating so_state before calling soo_poll(), call soo_poll() normally but avoid setting SS_CANTRCVMORE in the reader's so_state on first open. This fixes EOF detection in select/poll on the reader side when the write side is closed. Also set SS_ISDISCONNECTED when the writer count reaches zero so POLLHUP is set in revents. Unlike Unix domain sockets, we need to clear the EOF indicator after it has been read so that subsequent reads will block waiting for a new writer. This now passes regress.
-rw-r--r--sys/miscfs/fifofs/fifo_vnops.c26
1 files changed, 10 insertions, 16 deletions
diff --git a/sys/miscfs/fifofs/fifo_vnops.c b/sys/miscfs/fifofs/fifo_vnops.c
index 5b8c10fcb3f..c01becf6e5c 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.41 2014/09/14 14:17:26 jsg Exp $ */
+/* $OpenBSD: fifo_vnops.c,v 1.42 2014/10/09 16:36:36 millert Exp $ */
/* $NetBSD: fifo_vnops.c,v 1.18 1996/03/16 23:52:42 christos Exp $ */
/*
@@ -147,8 +147,8 @@ fifo_open(void *v)
return (error);
}
fip->fi_readers = fip->fi_writers = 0;
+ wso->so_state |= SS_CANTSENDMORE;
wso->so_snd.sb_lowat = PIPE_BUF;
- rso->so_state |= SS_CANTRCVMORE;
}
if (ap->a_mode & FREAD) {
fip->fi_readers++;
@@ -165,7 +165,7 @@ fifo_open(void *v)
goto bad;
}
if (fip->fi_writers == 1) {
- fip->fi_readsock->so_state &= ~SS_CANTRCVMORE;
+ fip->fi_readsock->so_state &= ~(SS_CANTRCVMORE|SS_ISDISCONNECTED);
if (fip->fi_readers > 0)
wakeup(&fip->fi_readers);
}
@@ -224,6 +224,9 @@ fifo_read(void *v)
ap->a_vp->v_fifoinfo->fi_writers == 0)
error = 0;
}
+ /* Clear EOF indicator so we have a clean slate for a new writer. */
+ if (error == 0)
+ rso->so_state &= ~(SS_CANTRCVMORE|SS_ISDISCONNECTED);
return (error);
}
@@ -287,24 +290,12 @@ fifo_poll(void *v)
{
struct vop_poll_args *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 = 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 = ap->a_vp->v_fifoinfo->fi_writesock;
@@ -344,8 +335,11 @@ fifo_close(void *v)
socantsendmore(fip->fi_writesock);
}
if (ap->a_fflag & FWRITE) {
- if (--fip->fi_writers == 0)
+ if (--fip->fi_writers == 0) {
+ /* SS_ISDISCONNECTED will result in POLLHUP */
+ fip->fi_readsock->so_state |= SS_ISDISCONNECTED;
socantrcvmore(fip->fi_readsock);
+ }
}
if (fip->fi_readers == 0 && fip->fi_writers == 0) {
error1 = soclose(fip->fi_readsock);