On 29/10/21(Fri) 14:47, Martin Pieuchot wrote:
> On 29/10/21(Fri) 10:50, Anton Lindqvist wrote:
> > On Fri, Oct 29, 2021 at 09:13:58AM +0100, Larry Hynes wrote:
> > > Hi
> > > 
> > > In last two snapshots I installed, poll seems to hang in certain
> > > circumstances.
> > > 
> > > Here's a reproducer, from Leah Neukirchen (cc'ed on this mail):
> 
> Thanks, do you agree to license it under ISC, as in 
> /usr/share/misc/license.template, so we can put it in src/regress?
> 
> > > 
> > > ------
> > > 
> > > #include <stdio.h>
> > > #include <poll.h>
> > > #include <unistd.h>
> > > 
> > > int
> > > main()
> > > {
> > >   struct pollfd fds[1];
> > >   
> > >   fds[0].fd = 0;
> > >   fds[0].events = POLLIN | POLLHUP;
> > >   close(0);
> > > 
> > >   printf("%d\n", poll(fds, 1, -1));
> > >   printf("%d\n", fds[0].revents & POLLNVAL);
> > > }
> > > 
> > > ------
> > > 
> > > When compiled and run, that should hang on latest snap. It would be
> > > expected to return immediately with POLLNVAL set.
> > 
> > I think poll() needs similar handling as select() recently gained.
> > Caution, only compile tested.
> 
> Here's a simpler fix, do not sleep at all if we already have something
> to report.

After some discussions with anton@ I believe we should instead go with a
version similar to what sys_select is doing.  It is necessary to call
ppollcollect() for FDs that are ready.

Here's anton@'s version without extra argument:

Index: kern/sys_generic.c
===================================================================
RCS file: /cvs/src/sys/kern/sys_generic.c,v
retrieving revision 1.138
diff -u -p -r1.138 sys_generic.c
--- kern/sys_generic.c  24 Oct 2021 11:23:22 -0000      1.138
+++ kern/sys_generic.c  29 Oct 2021 14:05:56 -0000
@@ -1128,7 +1128,7 @@ doppoll(struct proc *p, struct pollfd *f
 {
        struct kqueue_scan_state scan;
        struct pollfd pfds[4], *pl = pfds;
-       int error, nevents = 0;
+       int error, ncollected, nevents = 0;
        size_t sz;
 
        /* Standards say no more than MAX_OPEN; this is possibly better. */
@@ -1154,14 +1154,14 @@ doppoll(struct proc *p, struct pollfd *f
                dosigsuspend(p, *sigmask &~ sigcantmask);
 
        /* Register kqueue events */
-       *retval = ppollregister(p, pl, nfds, &nevents);
+       ncollected = ppollregister(p, pl, nfds, &nevents);
 
        /*
         * The poll/select family of syscalls has been designed to
         * block when file descriptors are not available, even if
         * there's nothing to wait for.
         */
-       if (nevents == 0) {
+       if (nevents == 0 && ncollected == 0) {
                uint64_t nsecs = INFSLP;
 
                if (timeout != NULL) {
@@ -1184,7 +1184,7 @@ doppoll(struct proc *p, struct pollfd *f
                struct kevent kev[KQ_NEVENTS];
                int i, ready, count;
 
-               /* Maxium number of events per iteration */
+               /* Maximum number of events per iteration */
                count = MIN(nitems(kev), nevents);
                ready = kqueue_scan(&scan, count, kev, timeout, p, &error);
 #ifdef KTRACE
@@ -1193,7 +1193,7 @@ doppoll(struct proc *p, struct pollfd *f
 #endif
                /* Convert back events that are ready. */
                for (i = 0; i < ready; i++)
-                       *retval += ppollcollect(p, &kev[i], pl, nfds);
+                       ncollected += ppollcollect(p, &kev[i], pl, nfds);
 
                /*
                 * Stop if there was an error or if we had enough
@@ -1205,6 +1205,7 @@ doppoll(struct proc *p, struct pollfd *f
                nevents -= ready;
        }
        kqueue_scan_finish(&scan);
+       *retval = ncollected;
 done:
        /*
         * NOTE: poll(2) is not restarted after a signal and EWOULDBLOCK is

Reply via email to