The poll(2) and select(2) system calls block until:

* the monitored set of file descriptors has a pending event,

* the timeout expires, or

* a signal has been received.

If the monitored fd set is empty, the system calls block until timeout
or signal. This is handled by special cases in the kernel.

This patch replaces p->p_kq with nowake as the wait channel in the
poll/select special cases. The code does not expect anything to happen
with the kqueue instance.

In principle, p->p_kq can receive unwanted wakeups. However,
kqueue_wakeup() does not call wakeup() if there is no blocked
kqueue_scan() invocation. Previously, the eager removal of poll/select
knotes also prevented kqueue wakeups.

OK?

Index: sys/kern/sys_generic.c
===================================================================
RCS file: src/sys/kern/sys_generic.c,v
retrieving revision 1.140
diff -u -p -r1.140 sys_generic.c
--- sys/kern/sys_generic.c      12 Nov 2021 04:34:22 -0000      1.140
+++ sys/kern/sys_generic.c      13 Nov 2021 06:07:54 -0000
@@ -671,7 +671,7 @@ dopselect(struct proc *p, int nd, fd_set
                                goto done;
                        nsecs = MAX(1, MIN(TIMESPEC_TO_NSEC(timeout), MAXTSLP));
                }
-               error = tsleep_nsec(&p->p_kq, PSOCK | PCATCH, "kqsel", nsecs);
+               error = tsleep_nsec(&nowake, PSOCK | PCATCH, "kqsel", nsecs);
                /* select is not restarted after signals... */
                if (error == ERESTART)
                        error = EINTR;
@@ -1166,7 +1166,7 @@ doppoll(struct proc *p, struct pollfd *f
                        nsecs = MAX(1, MIN(TIMESPEC_TO_NSEC(timeout), MAXTSLP));
                }
 
-               error = tsleep_nsec(&p->p_kq, PSOCK | PCATCH, "kqpoll", nsecs);
+               error = tsleep_nsec(&nowake, PSOCK | PCATCH, "kqpoll", nsecs);
                if (error == ERESTART)
                        error = EINTR;
                if (error == EWOULDBLOCK)

Reply via email to