Here is a better diff that passes the newly-updated regress test.
It does two extra things:

1) causes POLLHUP to be returned in revents on EOF

2) clears the EOF condition on read so when another writer
   connects we don't still have an EOF pending

Ultimately we should investigate using a separate named pipe
implementation instead of trying to emulate them using sockets.
Something like the FreeBSD approach of extending sys_pipe.c to
support named pipes is probably the way to go.

 - todd

Index: sys/miscfs/fifofs/fifo_vnops.c
===================================================================
RCS file: /cvs/src/sys/miscfs/fifofs/fifo_vnops.c,v
retrieving revision 1.41
diff -u -r1.41 fifo_vnops.c
--- sys/miscfs/fifofs/fifo_vnops.c      14 Sep 2014 14:17:26 -0000      1.41
+++ sys/miscfs/fifofs/fifo_vnops.c      9 Oct 2014 11:18:46 -0000
@@ -147,8 +147,8 @@
                        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 @@
                        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 @@
                    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 @@
 {
        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 @@
                        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);

Reply via email to