From e1689c92a61b81347430ae05ff2514edc4735157 Mon Sep 17 00:00:00 2001 From: Dan Cross Date: Sat, 11 May 2024 01:46:33 +0000 Subject: [PATCH 2/2] pps_fetch: introduce a helper to handle timeouts Introduce a helper function that handles providing a timeout so that we can wait for an event, and call it from the PPS_IOC_FETCH ioctl case. Modeled after the same code in FreeBSD. Signed-off-by: Dan Cross --- sys/kern/kern_clock.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c index f2f3c79ea8..01190746c4 100644 --- a/sys/kern/kern_clock.c +++ b/sys/kern/kern_clock.c @@ -1603,6 +1603,36 @@ get_approximate_time_t(void) return(gd->gd_time_seconds + bt->tv_sec); } +static int +pps_fetch_timeout(struct timespec *timeout, struct pps_state *pps) +{ + int to, err; + pps_seq_t *ap, *cp; + pps_seq_t a, c; + + to = INT_MAX; + if (timeout->tv_sec > -1) + to = tstohz_low(timeout); + + ap = &pps->ppsinfo.assert_sequence; + cp = &pps->ppsinfo.clear_sequence; + a = atomic_load_acq_int(ap); + c = atomic_load_acq_int(cp); + + while (a == atomic_load_acq_int(ap) && c == atomic_load_acq_int(cp)) { + err = tsleep(pps, PCATCH, "ppsfch", to); + if (err == EWOULDBLOCK) { + if (timeout->tv_sec < 0) + continue; + return (ETIMEDOUT); + } + if (err != 0) + return (err); + } + + return (0); +} + int pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) { @@ -1611,6 +1641,7 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) #ifdef PPS_SYNC struct pps_kcbind_args *kapi; #endif + int err; switch (cmd) { case PPS_IOC_CREATE: @@ -1635,8 +1666,11 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) fapi = (struct pps_fetch_args *)data; if (fapi->tsformat && fapi->tsformat != PPS_TSFMT_TSPEC) return (EINVAL); - if (fapi->timeout.tv_sec || fapi->timeout.tv_nsec) - return (EOPNOTSUPP); + if (fapi->timeout.tv_sec != 0 || fapi->timeout.tv_nsec != 0) { + err = pps_fetch_timeout(&fapi->timeout, pps); + if (err != 0) + return (err); + } pps->ppsinfo.current_mode = pps->ppsparam.mode; fapi->pps_info_buf = pps->ppsinfo; return (0); @@ -1663,7 +1697,7 @@ pps_ioctl(u_long cmd, caddr_t data, struct pps_state *pps) void pps_init(struct pps_state *pps) { - pps->ppscap |= PPS_TSFMT_TSPEC; + pps->ppscap |= PPS_TSFMT_TSPEC | PPS_CANWAIT; if (pps->ppscap & PPS_CAPTUREASSERT) pps->ppscap |= PPS_OFFSETASSERT; if (pps->ppscap & PPS_CAPTURECLEAR) @@ -1739,7 +1773,7 @@ pps_event(struct pps_state *pps, sysclock_t count, int event) ++ts.tv_sec; } - (*pseq)++; + atomic_add_rel_int(pseq, 1); *tsp = ts; if (foff) { @@ -1765,6 +1799,7 @@ pps_event(struct pps_state *pps, sysclock_t count, int event) hardpps(tsp, delta); } #endif + wakeup(pps); } /* -- 2.42.0