On Fri, Oct 29, 2021 at 04:08:39PM +0200, Martin Pieuchot wrote:
> 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:

Thanks, committed by now.

> 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