Currently, dopselect() and doppoll() call tsleep_nsec() without retry. cheloha@ asked if the functions should handle spurious wakeups. I guess such wakeups are unlikely with the nowake wait channel, but I am not sure if that is a safe guess.
The following diff adds the retrying. The code is a bit arduous, so the retry loop is put in a separate function that both poll and select use. Index: kern/sys_generic.c =================================================================== RCS file: src/sys/kern/sys_generic.c,v retrieving revision 1.141 diff -u -p -r1.141 sys_generic.c --- kern/sys_generic.c 16 Nov 2021 13:48:23 -0000 1.141 +++ kern/sys_generic.c 16 Nov 2021 13:50:08 -0000 @@ -90,6 +90,7 @@ int dopselect(struct proc *, int, fd_set int doppoll(struct proc *, struct pollfd *, u_int, struct timespec *, const sigset_t *, register_t *); void doselwakeup(struct selinfo *); +int selsleep(struct timespec *); int iovec_copyin(const struct iovec *uiov, struct iovec **iovp, struct iovec *aiov, @@ -664,19 +665,7 @@ dopselect(struct proc *p, int nd, fd_set * there's nothing to wait for. */ if (nevents == 0 && ncollected == 0) { - uint64_t nsecs = INFSLP; - - if (timeout != NULL) { - if (!timespecisset(timeout)) - goto done; - nsecs = MAX(1, MIN(TIMESPEC_TO_NSEC(timeout), MAXTSLP)); - } - error = tsleep_nsec(&nowake, PSOCK | PCATCH, "kqsel", nsecs); - /* select is not restarted after signals... */ - if (error == ERESTART) - error = EINTR; - if (error == EWOULDBLOCK) - error = 0; + error = selsleep(timeout); goto done; } @@ -849,6 +838,46 @@ selfalse(dev_t dev, int events, struct p } /* + * Sleep until a signal arrives or the optional timeout expires. + */ +int +selsleep(struct timespec *timeout) +{ + uint64_t end, now, nsecs; + int error; + + if (timeout != NULL) { + if (!timespecisset(timeout)) + return (0); + now = getnsecuptime(); + end = MIN(now + TIMESPEC_TO_NSEC(timeout), MAXTSLP); + if (end < now) + end = MAXTSLP; + } + + do { + if (timeout != NULL) + nsecs = MAX(1, end - now); + else + nsecs = INFSLP; + error = tsleep_nsec(&nowake, PSOCK | PCATCH, "selslp", nsecs); + if (timeout != NULL) { + now = getnsecuptime(); + if (now >= end) + break; + } + } while (error == 0); + + /* poll/select is not restarted after signals... */ + if (error == ERESTART) + error = EINTR; + if (error == EWOULDBLOCK) + error = 0; + + return (error); +} + +/* * Record a select request. */ void @@ -1158,19 +1187,7 @@ doppoll(struct proc *p, struct pollfd *f * there's nothing to wait for. */ if (nevents == 0 && ncollected == 0) { - uint64_t nsecs = INFSLP; - - if (timeout != NULL) { - if (!timespecisset(timeout)) - goto done; - nsecs = MAX(1, MIN(TIMESPEC_TO_NSEC(timeout), MAXTSLP)); - } - - error = tsleep_nsec(&nowake, PSOCK | PCATCH, "kqpoll", nsecs); - if (error == ERESTART) - error = EINTR; - if (error == EWOULDBLOCK) - error = 0; + error = selsleep(timeout); goto done; }