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) {