kernel - More kqueue work
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 13 Aug 2010 21:05:45 +0000 (14:05 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 13 Aug 2010 21:05:45 +0000 (14:05 -0700)
* Only set EV_EOF in the read filter after all pending data has
  been exhausted.

* This also fixes a bug where the read filter was not setting data
  ready on EOF when data was pending in the buffer.

* Fix bugs in the poll copyout handler.  An EOF condition does not
  prevent other flags from getting set.

sys/kern/sys_generic.c
sys/kern/sys_pipe.c
sys/kern/uipc_socket.c
sys/vfs/fifofs/fifo_vnops.c

index 8d9786a..733326b 100644 (file)
@@ -1287,6 +1287,7 @@ poll_copyout(void *arg, struct kevent *kevp, int count, int *res)
        struct poll_kevent_copyin_args *pkap;
        struct pollfd *pfd;
        struct kevent kev;
+       int count_res;
        int i;
        u_int pi;
 
@@ -1314,14 +1315,16 @@ poll_copyout(void *arg, struct kevent *kevp, int count, int *res)
                if (kevp[i].ident == pfd->fd) {
                        /*
                         * A single descriptor may generate an error against
-                        * more than one filter, make sure to set the appropriate
-                        * flags but do not increment (*res) more than once.
+                        * more than one filter, make sure to set the
+                        * appropriate flags but do not increment (*res)
+                        * more than once.
                         */
+                       count_res = (pfd->revents == 0);
                        if (kevp[i].flags & EV_ERROR) {
                                switch(kevp[i].data) {
                                case EBADF:
                                        /* Bad file descriptor */
-                                       if (pfd->revents == 0)
+                                       if (count_res)
                                                ++*res;
                                        pfd->revents |= POLLNVAL;
                                        break;
@@ -1339,7 +1342,7 @@ poll_copyout(void *arg, struct kevent *kevp, int count, int *res)
                                        if (kevp[i].filter != EVFILT_READ &&
                                            kevp[i].filter != EVFILT_WRITE &&
                                            kevp[i].data != EOPNOTSUPP) {
-                                               if (pfd->revents == 0)
+                                               if (count_res == 0)
                                                        ++*res;
                                                pfd->revents |= POLLERR;
                                        }
@@ -1355,12 +1358,8 @@ poll_copyout(void *arg, struct kevent *kevp, int count, int *res)
                                continue;
                        }
 
-                       if (kevp[i].flags & EV_EOF) {
-                               if (pfd->revents == 0)
-                                       ++*res;
+                       if (kevp[i].flags & EV_EOF)
                                pfd->revents |= POLLHUP;
-                               continue;
-                       }
 
                        switch (kevp[i].filter) {
                        case EVFILT_READ:
@@ -1388,8 +1387,8 @@ poll_copyout(void *arg, struct kevent *kevp, int count, int *res)
                                        pi, pkap->nfds, pfd->fd, pfd->revents);
                        }
 
-                       ++*res;
-                       continue;
+                       if (count_res && pfd->revents)
+                               ++*res;
                } else {
                        if (nseldebug) {
                                kprintf("poll index %d mismatch %ju/%d\n",
index c63595a..feda78d 100644 (file)
@@ -1304,7 +1304,11 @@ filt_piperead(struct knote *kn, long hint)
        lwkt_gettoken(&rpipe->pipe_wlock);
 
        kn->kn_data = rpipe->pipe_buffer.windex - rpipe->pipe_buffer.rindex;
-       if (rpipe->pipe_state & PIPE_REOF) {
+
+       /*
+        * Only set EOF if all data has been exhausted
+        */
+       if ((rpipe->pipe_state & PIPE_REOF) && kn->kn_data == 0) {
                kn->kn_flags |= EV_EOF; 
                ready = 1;
        }
index 39f19ac..a684650 100644 (file)
@@ -1756,7 +1756,11 @@ filt_soread(struct knote *kn, long hint)
                return (0);
        }
        kn->kn_data = so->so_rcv.ssb_cc;
-       if (so->so_state & SS_CANTRCVMORE) {
+
+       /*
+        * Only set EOF if all data has been exhausted.
+        */
+       if ((so->so_state & SS_CANTRCVMORE) && kn->kn_data == 0) {
                kn->kn_flags |= EV_EOF; 
                kn->kn_fflags = so->so_error;
                return (1);
index 2c35796..7020de5 100644 (file)
@@ -422,7 +422,7 @@ filt_fiforead(struct knote *kn, long hint)
 
        lwkt_gettoken(&vp->v_token);
        kn->kn_data = so->so_rcv.ssb_cc;
-       if (so->so_state & SS_ISDISCONNECTED) {
+       if ((so->so_state & SS_ISDISCONNECTED) && kn->kn_data == 0) {
                kn->kn_flags |= EV_EOF;
                lwkt_reltoken(&vp->v_token);
                return (1);