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):
> 
> ------
> 
> #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.

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 08:48:54 -0000
@@ -81,7 +81,7 @@ int kqpoll_debug = 0;
 
 int pselregister(struct proc *, fd_set *[], fd_set *[], int, int *, int *);
 int pselcollect(struct proc *, struct kevent *, fd_set *[], int *);
-int ppollregister(struct proc *, struct pollfd *, int, int *);
+int ppollregister(struct proc *, struct pollfd *, int, int *, int *);
 int ppollcollect(struct proc *, struct kevent *, struct pollfd *, u_int);
 
 int pollout(struct pollfd *, struct pollfd *, u_int);
@@ -978,7 +978,8 @@ again:
  * At most 3 events can correspond to a single pollfd.
  */
 int
-ppollregister(struct proc *p, struct pollfd *pl, int nfds, int *nregistered)
+ppollregister(struct proc *p, struct pollfd *pl, int nfds, int *nregistered,
+    int *ncollected)
 {
        int i, nkev, nevt, errcount = 0, forcehup = 0;
        struct kevent kev[3], *kevp;
@@ -1029,6 +1030,8 @@ ppollregister(struct proc *p, struct pol
                nevt = ppollregister_evts(p, kev, nkev, &pl[i]);
                if (nevt == 0 && !forcehup)
                        errcount++;
+               if (nevt == 0)
+                       (*ncollected)++;
                *nregistered += nevt;
        }
 
@@ -1128,7 +1131,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 = 0, nevents = 0;
        size_t sz;
 
        /* Standards say no more than MAX_OPEN; this is possibly better. */
@@ -1154,14 +1157,14 @@ doppoll(struct proc *p, struct pollfd *f
                dosigsuspend(p, *sigmask &~ sigcantmask);
 
        /* Register kqueue events */
-       *retval = ppollregister(p, pl, nfds, &nevents);
+       *retval = ppollregister(p, pl, nfds, &nevents, &ncollected);
 
        /*
         * 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) {

Reply via email to