Index: kern/kern_time.c =================================================================== RCS file: /cvsroot/src/sys/kern/kern_time.c,v retrieving revision 1.221 diff -d -p -u -r1.221 kern_time.c --- kern/kern_time.c 23 Feb 2023 02:57:17 -0000 1.221 +++ kern/kern_time.c 24 Dec 2023 01:43:17 -0000 @@ -405,7 +405,8 @@ nanosleep1(struct lwp *l, clockid_t cloc struct timespec rmtstart; int error, timo; - if ((error = ts2timo(clock_id, flags, rqt, &timo, &rmtstart)) != 0) { + error = ts2timo(clock_id, flags, rqt, &timo, &rmtstart, false); + if (error != 0) { if (error == ETIMEDOUT) { error = 0; if (rmt != NULL) @@ -414,21 +415,21 @@ nanosleep1(struct lwp *l, clockid_t cloc return error; } - /* - * Avoid inadvertently sleeping forever - */ - if (timo == 0) - timo = 1; -again: - error = kpause("nanoslp", true, timo, NULL); - if (error == EWOULDBLOCK) +slowagain: + if (timo > 0) { + error = kpause("nanoslp", true, timo, NULL); + if (error == EWOULDBLOCK) + error = 0; + } else { error = 0; + } if (rmt != NULL || error == 0) { struct timespec rmtend; struct timespec t0; struct timespec *t; int err; +quickagain: err = clock_gettime1(clock_id, &rmtend); if (err != 0) return err; @@ -449,9 +450,20 @@ again: if (t->tv_sec < 0) timespecclear(t); if (error == 0) { - timo = tstohz(t); - if (timo > 0) - goto again; +/* XXXSB start grotty hack part 2 */ + if (t->tv_sec == 0 && + t->tv_nsec != 0 && + t->tv_nsec / 1000 < tick) { + yield(); + goto quickagain; + } + + timo = tstohz_low(t); +/* XXXSB end grotty hack part 2 */ + + if (t->tv_sec != 0 || t->tv_nsec != 0) { + goto slowagain; + } } } @@ -1396,8 +1408,8 @@ dotimer_settime(int timerid, struct itim if (pts == NULL || timerid < 2 || timerid >= TIMER_MAX) return EINVAL; val = *value; - if ((error = itimespecfix(&val.it_value)) != 0 || - (error = itimespecfix(&val.it_interval)) != 0) + if ((error = itimespecfix(&val.it_value, true)) != 0 || + (error = itimespecfix(&val.it_interval, true)) != 0) return error; itimer_lock(); @@ -1636,7 +1648,8 @@ dosetitimer(struct proc *p, int which, s if ((u_int)which > ITIMER_MONOTONIC) return EINVAL; - if (itimerfix(&itvp->it_value) || itimerfix(&itvp->it_interval)) + if (itimerfix(&itvp->it_value, true) || + itimerfix(&itvp->it_interval, true)) return EINVAL; /* Index: kern/subr_time.c =================================================================== RCS file: /cvsroot/src/sys/kern/subr_time.c,v retrieving revision 1.38 diff -d -p -u -r1.38 subr_time.c --- kern/subr_time.c 8 Jul 2023 20:02:10 -0000 1.38 +++ kern/subr_time.c 24 Dec 2023 01:43:18 -0000 @@ -161,63 +161,99 @@ tstohz(const struct timespec *ts) return tvtohz(&tv); } +/* XXXSB start grotty hack part 1 */ +/* XXXSB from DragonFly */ +int +tstohz_low(const struct timespec *ts) +{ + int ticks; + uint64_t sec; + + sec = ts->tv_sec; + if (sec <= INT_MAX / hz) { + ticks = (int)(sec * hz + ts->tv_nsec / (tick * 1000)); + if (ticks > 1) { + /* XXX ugh, sometimes we sleep too long, compensate */ + ticks--; + } + } else { + ticks = INT_MAX; + } + return ticks; +} +/* XXXSB end grotty hack part 1 */ + /* * Check that a proposed value to load into the .it_value or - * .it_interval part of an interval timer is acceptable, and - * fix it to have at least minimal value (i.e. if it is less - * than the resolution of the clock, round it up.). We don't - * timeout the 0,0 value because this means to disable the - * timer or the interval. + * .it_interval part of an interval timer is acceptable. If the + * roundtick parameter is true, fix it to have at least minimal + * value (i.e. if it is less than the resolution of the clock, + * round it up.). We don't timeout the 0,0 value because this + * means to disable the timer or the interval. + */ int -itimerfix(struct timeval *tv) +itimerfix(struct timeval *tv, bool roundtick) { if (tv->tv_usec < 0 || tv->tv_usec >= 1000000) return EINVAL; if (tv->tv_sec < 0) return ETIMEDOUT; - if (tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) + if (roundtick && + tv->tv_sec == 0 && tv->tv_usec != 0 && tv->tv_usec < tick) tv->tv_usec = tick; return 0; } int -itimespecfix(struct timespec *ts) +itimespecfix(struct timespec *ts, bool roundtick) { if (ts->tv_nsec < 0 || ts->tv_nsec >= 1000000000) return EINVAL; if (ts->tv_sec < 0) return ETIMEDOUT; - if (ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000) + if (roundtick && + ts->tv_sec == 0 && ts->tv_nsec != 0 && ts->tv_nsec < tick * 1000) ts->tv_nsec = tick * 1000; return 0; } int -inittimeleft(struct timespec *ts, struct timespec *sleepts) +inittimeleft(struct timespec *ts, struct timespec *sleepts, bool roundtick) { - if (itimespecfix(ts)) { + if (itimespecfix(ts, roundtick)) { return -1; } KASSERT(ts->tv_sec >= 0); - getnanouptime(sleepts); + if (roundtick) { + /* accurate enough for tick-based intervals */ + getnanouptime(sleepts); + } else { + nanouptime(sleepts); + } return 0; } int -gettimeleft(struct timespec *ts, struct timespec *sleepts) +gettimeleft(struct timespec *ts, struct timespec *sleepts, bool roundtick) { struct timespec now, sleptts; + int timo; KASSERT(ts->tv_sec >= 0); /* * Reduce ts by elapsed time based on monotonic time scale. */ - getnanouptime(&now); + if (roundtick) { + /* accurate enough for tick-based intervals */ + getnanouptime(&now); + } else { + nanouptime(&now); + } KASSERT(timespeccmp(sleepts, &now, <=)); timespecsub(&now, sleepts, &sleptts); *sleepts = now; @@ -228,7 +264,12 @@ gettimeleft(struct timespec *ts, struct } timespecsub(ts, &sleptts, ts); - return tstohz(ts); + if (roundtick) { + timo = tstohz(ts); + } else { + timo = tstohz_low(ts); + } + return timo; } void @@ -312,7 +353,7 @@ clock_gettime1(clockid_t clock_id, struc */ int ts2timo(clockid_t clock_id, int flags, struct timespec *ts, - int *timo, struct timespec *start) + int *timo, struct timespec *start, bool roundtick) { int error; struct timespec tsd; @@ -334,15 +375,20 @@ ts2timo(clockid_t clock_id, int flags, s timespecsub(ts, &tsd, ts); } - error = itimespecfix(ts); + error = itimespecfix(ts, false); if (error != 0) return error; if (ts->tv_sec == 0 && ts->tv_nsec == 0) return ETIMEDOUT; - *timo = tstohz(ts); - KASSERT(*timo > 0); + if (roundtick) { + *timo = tstohz(ts); + KASSERT(*timo > 0); + } else { + *timo = tstohz_low(ts); + KASSERT(*timo >= 0); + } return 0; } Index: kern/sys_select.c =================================================================== RCS file: /cvsroot/src/sys/kern/sys_select.c,v retrieving revision 1.66 diff -d -p -u -r1.66 sys_select.c --- kern/sys_select.c 15 Oct 2023 10:29:34 -0000 1.66 +++ kern/sys_select.c 24 Dec 2023 01:43:18 -0000 @@ -243,7 +245,7 @@ sel_do_scan(const char *opname, void *fd int error, timo; timo = 0; - if (ts && inittimeleft(ts, &sleepts) == -1) { + if (ts && inittimeleft(ts, &sleepts, false) == -1) { return EINVAL; } @@ -296,8 +298,14 @@ sel_do_scan(const char *opname, void *fd } if (error || *retval) break; - if (ts && (timo = gettimeleft(ts, &sleepts)) <= 0) - break; + if (ts) { + timo = gettimeleft(ts, &sleepts, false); +/* XXXSB start grotty hack part 2 */ + if (ts->tv_sec == 0 && ts->tv_nsec == 0) { + break; + } +/* XXXSB end grotty hack part 2 */ + } /* * Acquire the lock and perform the (re)checks. Note, if * collision has occurred, then our state does not matter, @@ -322,14 +330,35 @@ state_check: selclear(); continue; } +/* XXXSB start grotty hack part 3 */ + if (ts && + ts->tv_sec == 0 && + ts->tv_nsec != 0 && + timo == 0) + { + mutex_spin_exit(lock); + yield(); + continue; + } +/* XXXSB end grotty hack part 3 */ + /* Nothing happen, therefore - sleep. */ l->l_selflag = SEL_BLOCKING; KASSERT(l->l_blcnt == 0); (void)sleepq_enter(&sc->sc_sleepq, l, lock); sleepq_enqueue(&sc->sc_sleepq, sc, opname, &select_sobj, true); error = sleepq_block(timo, true, &select_sobj, 0); +/* XXXSB start grotty hack part 4 */ + if (ts) { +// printf("%s:%d ts = %ld.%09ld\n", __func__, __LINE__, ts->tv_sec, ts->tv_nsec); + timo = gettimeleft(ts, &sleepts, false); + } +/* XXXSB end grotty hack part 4 */ if (error != 0) { - break; + if (error == EWOULDBLOCK && ts && + ts->tv_sec == 0 && ts->tv_nsec == 0) { + break; + } } /* Awoken: need to check the state. */ goto state_check; Index: kern/sys_sig.c =================================================================== RCS file: /cvsroot/src/sys/kern/sys_sig.c,v retrieving revision 1.57 diff -d -p -u -r1.57 sys_sig.c --- kern/sys_sig.c 4 Oct 2023 20:42:38 -0000 1.57 +++ kern/sys_sig.c 24 Dec 2023 01:43:18 -0000 @@ -753,7 +753,7 @@ sigtimedwait1(struct lwp *l, const struc if (error) return error; - if ((error = itimespecfix(&ts)) != 0) + if ((error = itimespecfix(&ts, true)) != 0) return error; timo = tstohz(&ts); Index: sys/timevar.h =================================================================== RCS file: /cvsroot/src/sys/sys/timevar.h,v retrieving revision 1.51 diff -d -p -u -r1.51 timevar.h --- sys/timevar.h 17 Jul 2023 13:44:24 -0000 1.51 +++ sys/timevar.h 24 Dec 2023 01:43:18 -0000 @@ -187,7 +187,8 @@ void getnanoboottime(struct timespec *); void getmicroboottime(struct timeval *); /* Other functions */ -int ts2timo(clockid_t, int, struct timespec *, int *, struct timespec *); +int ts2timo(clockid_t, int, struct timespec *, int *, struct timespec *, + bool); void adjtime1(const struct timeval *, struct timeval *, struct proc *); int clock_getres1(clockid_t, struct timespec *); int clock_gettime1(clockid_t, struct timespec *); @@ -202,8 +203,8 @@ int tshzto(const struct timespec *); int tshztoup(const struct timespec *); int tvhzto(const struct timeval *); void inittimecounter(void); -int itimerfix(struct timeval *); -int itimespecfix(struct timespec *); +int itimerfix(struct timeval *, bool); +int itimespecfix(struct timespec *, bool); int ppsratecheck(struct timeval *, int *, int); int ratecheck(struct timeval *, const struct timeval *); int settime(struct proc *p, struct timespec *); @@ -214,9 +215,10 @@ int settimeofday1(const struct timeval * int timer_create1(timer_t *, clockid_t, struct sigevent *, copyin_t, struct lwp *); int tstohz(const struct timespec *); +int tstohz_low(const struct timespec *); int tvtohz(const struct timeval *); -int inittimeleft(struct timespec *, struct timespec *); -int gettimeleft(struct timespec *, struct timespec *); +int inittimeleft(struct timespec *, struct timespec *, bool); +int gettimeleft(struct timespec *, struct timespec *, bool); void timerupcall(struct lwp *); void time_init(void); bool time_wraps(struct timespec *, struct timespec *);