Ah, good feedback. Applied in bd8621c6cd8a. Anything else?

Warner

On Fri, Jun 13, 2025 at 2:17 AM Konstantin Belousov <kostik...@gmail.com> wrote:
>
> On Thu, Jun 12, 2025 at 06:25:40PM +0000, Warner Losh wrote:
> > The branch main has been updated by imp:
> >
> > URL: 
> > https://cgit.FreeBSD.org/src/commit/?id=7b7ba7857ce8be0bf6ab905d936d8ba1363e4ec2
> >
> > commit 7b7ba7857ce8be0bf6ab905d936d8ba1363e4ec2
> > Author:     Nathan Whitehorn <nwhiteh...@freebsd.org>
> > AuthorDate: 2025-06-12 17:52:30 +0000
> > Commit:     Warner Losh <i...@freebsd.org>
> > CommitDate: 2025-06-12 18:25:31 +0000
> >
> >     Implement CLOCK_TAI
> >
> >     Provide a clock through clock_gettime() that returns the current TAI
> >     time (UTC without leap seconds) as a complement to CLOCK_REALTIME. This
> >     provides compatibility with Linux, which also provides a CLOCK_TAI since
> >     kernel 2.6.26, and this seems to be becoming the standard way to acquire
> >     TAI time. Unlike Linux, this code will return EINVAL if the TAI offset
> >     (set by ntpd, ptpd, etc.) is not known since it seems pathological for
> >     CLOCK_TAI to silently give the wrong (UTC) time if the offset is not
> >     known as it does on Linux.
> >
> >     Reviewed by: imp
> >     Differential Revision:  https://reviews.freebsd.org/D46268
> > ---
> >  lib/libsys/_umtx_op.2             |  2 ++
> >  lib/libsys/clock_gettime.2        | 14 ++++++++++--
> >  lib/libsys/nanosleep.2            |  4 +++-
> >  lib/libsys/timer_create.2         |  3 ++-
> >  lib/libthr/thread/thr_condattr.c  |  1 +
> >  share/man/man3/pthread_condattr.3 |  3 ++-
> >  sys/kern/kern_ntptime.c           |  3 ++-
> >  sys/kern/kern_tc.c                | 10 ++++++++-
> >  sys/kern/kern_time.c              | 46 
> > ++++++++++++++++++++++++++-------------
> >  sys/kern/kern_umtx.c              |  7 ++++--
> >  sys/sys/_clock_id.h               |  4 ++++
> >  sys/sys/timeffc.h                 |  4 +++-
> >  sys/sys/timex.h                   |  2 +-
> >  13 files changed, 77 insertions(+), 26 deletions(-)
> >
> > diff --git a/lib/libsys/_umtx_op.2 b/lib/libsys/_umtx_op.2
> > index 974850fb8425..c590f8e8e0c8 100644
> > --- a/lib/libsys/_umtx_op.2
> > +++ b/lib/libsys/_umtx_op.2
> > @@ -210,6 +210,8 @@ Valid clock identifiers are a subset of those for
> >  .It
> >  .Dv CLOCK_SECOND
> >  .It
> > +.Dv CLOCK_TAI
> > +.It
> >  .Dv CLOCK_UPTIME
> >  .It
> >  .Dv CLOCK_UPTIME_FAST
> > diff --git a/lib/libsys/clock_gettime.2 b/lib/libsys/clock_gettime.2
> > index fcdc5be498f2..1dcfd9d1faf7 100644
> > --- a/lib/libsys/clock_gettime.2
> > +++ b/lib/libsys/clock_gettime.2
> > @@ -27,7 +27,7 @@
> >  .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >  .\" SUCH DAMAGE.
> >  .\"
> > -.Dd June 28, 2024
> > +.Dd August 10, 2024
> >  .Dt CLOCK_GETTIME 2
> >  .Os
> >  .Sh NAME
> > @@ -99,11 +99,20 @@ query, using an in-kernel cached value of the current 
> > second.
> >  Returns the execution time of the calling process.
> >  .It Dv CLOCK_THREAD_CPUTIME_ID
> >  Returns the execution time of the calling thread.
> > +.It Dv CLOCK_TAI
> > +Increments in SI seconds like a wall clock.
> > +It uses a 1970 epoch and implements the TAI timescale.
> > +Similar to CLOCK_REALTIME, but without leap seconds.
> .Dv CLOCK_REALTIME
> > +It will increase monotonically during a leap second.
> > +Will return EINVAL if the current offset between TAI and UTC is not known,
> .Er EINVAL
> > +which may be the case early in boot before NTP or other time daemon has
> > +synchronized.
> >  .El
> >  .Pp
> >  The clock IDs
> >  .Dv CLOCK_BOOTTIME ,
> >  .Dv CLOCK_REALTIME ,
> > +.Dv CLOCK_TAI ,
> >  .Dv CLOCK_MONOTONIC ,
> >  and
> >  .Dv CLOCK_UPTIME
> > @@ -202,7 +211,8 @@ The clock IDs
> >  .Dv CLOCK_MONOTONIC_PRECISE ,
> >  .Dv CLOCK_REALTIME_FAST ,
> >  .Dv CLOCK_REALTIME_PRECISE ,
> > -.Dv CLOCK_SECOND
> > +.Dv CLOCK_SECOND ,
> > +.Dv CLOCK_TAI ,
> >  .Dv CLOCK_UPTIME ,
> >  .Dv CLOCK_UPTIME_FAST ,
> >  and
> > diff --git a/lib/libsys/nanosleep.2 b/lib/libsys/nanosleep.2
> > index ba9aae1edf57..290565dbd6e1 100644
> > --- a/lib/libsys/nanosleep.2
> > +++ b/lib/libsys/nanosleep.2
> > @@ -27,7 +27,7 @@
> >  .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> >  .\" SUCH DAMAGE.
> >  .\"
> > -.Dd April 29, 2025
> > +.Dd May 3, 2025
> >  .Dt NANOSLEEP 2
> >  .Os
> >  .Sh NAME
> > @@ -116,6 +116,8 @@ CLOCK_REALTIME_PRECISE
> >  .It
> >  CLOCK_SECOND
> >  .It
> > +CLOCK_TAI
> > +.It
> >  CLOCK_UPTIME
> >  .It
> >  CLOCK_UPTIME_FAST
> > diff --git a/lib/libsys/timer_create.2 b/lib/libsys/timer_create.2
> > index e8489b390845..8f6ff2e27c51 100644
> > --- a/lib/libsys/timer_create.2
> > +++ b/lib/libsys/timer_create.2
> > @@ -126,7 +126,8 @@ the value of the timer ID.
> >  This implementation supports a
> >  .Fa clock_id
> >  of
> > -.Dv CLOCK_REALTIME
> > +.Dv CLOCK_REALTIME ,
> > +.Dv CLOCK_TAI ,
> >  or
> >  .Dv CLOCK_MONOTONIC .
> >  .Pp
> > diff --git a/lib/libthr/thread/thr_condattr.c 
> > b/lib/libthr/thread/thr_condattr.c
> > index 0dc3e52bab5e..dc56363fc084 100644
> > --- a/lib/libthr/thread/thr_condattr.c
> > +++ b/lib/libthr/thread/thr_condattr.c
> > @@ -94,6 +94,7 @@ _pthread_condattr_setclock(pthread_condattr_t *attr, 
> > clockid_t clock_id)
> >       if (attr == NULL || *attr == NULL)
> >               return (EINVAL);
> >       if (clock_id != CLOCK_REALTIME &&
> > +         clock_id != CLOCK_TAI &&
> >           clock_id != CLOCK_VIRTUAL &&
> >           clock_id != CLOCK_PROF &&
> >           clock_id != CLOCK_MONOTONIC) {
> > diff --git a/share/man/man3/pthread_condattr.3 
> > b/share/man/man3/pthread_condattr.3
> > index 96d30263d7f2..33ad904f9a3d 100644
> > --- a/share/man/man3/pthread_condattr.3
> > +++ b/share/man/man3/pthread_condattr.3
> > @@ -85,7 +85,8 @@ in
> >  .Xr pthread_cond_timedwait 3
> >  and may be set to
> >  .Dv CLOCK_REALTIME
> > -(default)
> > +(default),
> > +.Dv CLOCK_TAI ,
> >  or
> >  .Dv CLOCK_MONOTONIC .
> >  .Pp
> > diff --git a/sys/kern/kern_ntptime.c b/sys/kern/kern_ntptime.c
> > index 65746021028b..892a6798ab1f 100644
> > --- a/sys/kern/kern_ntptime.c
> > +++ b/sys/kern/kern_ntptime.c
> > @@ -504,7 +504,7 @@ sys_ntp_adjtime(struct thread *td, struct 
> > ntp_adjtime_args *uap)
> >   * simulation.
> >   */
> >  void
> > -ntp_update_second(int64_t *adjustment, time_t *newsec)
> > +ntp_update_second(int64_t *adjustment, time_t *newsec, long *tai_off)
> >  {
> >       int tickrate;
> >       l_fp ftemp;             /* 32/64-bit temporary */
> > @@ -624,6 +624,7 @@ ntp_update_second(int64_t *adjustment, time_t *newsec)
> >               L_ADD(time_adj, ftemp);
> >       }
> >       *adjustment = time_adj;
> > +     *tai_off = time_tai;
> >
> >  #ifdef PPS_SYNC
> >       if (pps_valid > 0)
> > diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c
> > index a797a101bf6f..e85812e415c7 100644
> > --- a/sys/kern/kern_tc.c
> > +++ b/sys/kern/kern_tc.c
> > @@ -72,6 +72,7 @@ struct timehands {
> >       uint64_t                th_scale;
> >       u_int                   th_large_delta;
> >       u_int                   th_offset_count;
> > +     long                    th_tai_offset;
> >       struct bintime          th_offset;
> >       struct bintime          th_bintime;
> >       struct timeval          th_microtime;
> > @@ -1066,6 +1067,7 @@ sysclock_getsnapshot(struct sysclock_snap 
> > *clock_snap, int fast)
> >               th = timehands;
> >               gen = atomic_load_acq_int(&th->th_generation);
> >               fbi->th_scale = th->th_scale;
> > +             fbi->th_tai_offset = th->th_tai_offset;
> >               fbi->tick_time = th->th_offset;
> >  #ifdef FFCLOCK
> >               ffth = fftimehands;
> > @@ -1139,6 +1141,11 @@ sysclock_snap2bintime(struct sysclock_snap *cs, 
> > struct bintime *bt,
> >                       getboottimebin(&boottimebin);
> >                       bintime_add(bt, &boottimebin);
> >               }
> > +             if (!(flags & FBCLOCK_LEAPSEC)) {
> > +                     if (cs->fb_info.th_tai_offset == 0)
> > +                             return (EINVAL);
> > +                     bt->sec += cs->fb_info.th_tai_offset;
> > +             }
> >               break;
> >  #ifdef FFCLOCK
> >       case SYSCLOCK_FFWD:
> > @@ -1433,7 +1440,8 @@ tc_windup(struct bintime *new_boottimebin)
> >
> >               do {
> >                       t = bt.sec;
> > -                     ntp_update_second(&th->th_adjustment, &bt.sec);
> > +                     ntp_update_second(&th->th_adjustment, &bt.sec,
> > +                         &th->th_tai_offset);
> >                       if (bt.sec != t)
> >                               th->th_boottime.sec += bt.sec - t;
> >                       --i;
> > diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
> > index 0c31c1563d99..5960136eb515 100644
> > --- a/sys/kern/kern_time.c
> > +++ b/sys/kern/kern_time.c
> > @@ -49,6 +49,7 @@
> >  #include <sys/proc.h>
> >  #include <sys/posix4.h>
> >  #include <sys/time.h>
> > +#include <sys/timeffc.h>
> >  #include <sys/timers.h>
> >  #include <sys/timetc.h>
> >  #include <sys/vnode.h>
> > @@ -60,7 +61,7 @@
> >  #include <vm/vm_extern.h>
> >  #include <vm/uma.h>
> >
> > -#define MAX_CLOCKS   (CLOCK_MONOTONIC+1)
> > +#define MAX_CLOCKS   (CLOCK_TAI+1)
> >  #define CPUCLOCK_BIT         0x80000000
> >  #define CPUCLOCK_PROCESS_BIT 0x40000000
> >  #define CPUCLOCK_ID_MASK     (~(CPUCLOCK_BIT|CPUCLOCK_PROCESS_BIT))
> > @@ -101,7 +102,6 @@ static int        realtimer_gettime(struct itimer *, 
> > struct itimerspec *);
> >  static int   realtimer_settime(struct itimer *, int,
> >                       struct itimerspec *, struct itimerspec *);
> >  static int   realtimer_delete(struct itimer *);
> > -static void  realtimer_clocktime(clockid_t, struct timespec *);
> >  static void  realtimer_expire(void *);
> >  static void  realtimer_expire_l(struct itimer *it, bool proc_locked);
> >
> > @@ -318,7 +318,10 @@ int
> >  kern_clock_gettime(struct thread *td, clockid_t clock_id, struct timespec 
> > *ats)
> >  {
> >       struct timeval sys, user;
> > +     struct sysclock_snap clk;
> > +     struct bintime bt;
> >       struct proc *p;
> > +     int err;
> We usually spell it as 'error'.
>
> >
> >       p = td->td_proc;
> >       switch (clock_id) {
> > @@ -329,6 +332,14 @@ kern_clock_gettime(struct thread *td, clockid_t 
> > clock_id, struct timespec *ats)
> >       case CLOCK_REALTIME_FAST:
> >               getnanotime(ats);
> >               break;
> > +     case CLOCK_TAI:
> > +             sysclock_getsnapshot(&clk, 0);
> > +             err = sysclock_snap2bintime(&clk, &bt, clk.sysclock_active,
> > +                 (clk.sysclock_active == SYSCLOCK_FFWD) ? FFCLOCK_LERP : 
> > 0);
> Extra ()
>
> > +             if (err)
>         if (err != 0)
>
> > +                     return (err);
> > +             bintime2timespec(&bt, ats);
> > +             break;
> >       case CLOCK_VIRTUAL:
> >               PROC_LOCK(p);
> >               PROC_STATLOCK(p);
> > @@ -451,6 +462,7 @@ kern_clock_getres(struct thread *td, clockid_t 
> > clock_id, struct timespec *ts)
> >       case CLOCK_REALTIME:
> >       case CLOCK_REALTIME_FAST:
> >       case CLOCK_REALTIME_PRECISE:
> > +     case CLOCK_TAI:
> >       case CLOCK_MONOTONIC:
> >       case CLOCK_MONOTONIC_FAST:
> >       case CLOCK_MONOTONIC_PRECISE:
> > @@ -516,6 +528,7 @@ kern_clock_nanosleep(struct thread *td, clockid_t 
> > clock_id, int flags,
> >               return (EINVAL);
> >       switch (clock_id) {
> >       case CLOCK_REALTIME:
> > +     case CLOCK_TAI:
> >               precise = nanosleep_precise;
> >               is_abs_real = (flags & TIMER_ABSTIME) != 0;
> >               break;
> > @@ -1167,6 +1180,7 @@ itimer_start(void)
> >               NULL, NULL, itimer_init, itimer_fini, UMA_ALIGN_PTR, 0);
> >       register_posix_clock(CLOCK_REALTIME,  &rt_clock);
> >       register_posix_clock(CLOCK_MONOTONIC, &rt_clock);
> > +     register_posix_clock(CLOCK_TAI, &rt_clock);
> >       p31b_setcfg(CTL_P1003_1B_TIMERS, 200112L);
> >       p31b_setcfg(CTL_P1003_1B_DELAYTIMER_MAX, INT_MAX);
> >       p31b_setcfg(CTL_P1003_1B_TIMER_MAX, TIMER_MAX);
> > @@ -1327,6 +1341,7 @@ kern_ktimer_create(struct thread *td, clockid_t 
> > clock_id, struct sigevent *evp,
> >               switch (clock_id) {
> >               default:
> >               case CLOCK_REALTIME:
> > +             case CLOCK_TAI:
> >                       it->it_sigev.sigev_signo = SIGALRM;
> >                       break;
> >               case CLOCK_VIRTUAL:
> > @@ -1570,10 +1585,14 @@ static int
> >  realtimer_gettime(struct itimer *it, struct itimerspec *ovalue)
> >  {
> >       struct timespec cts;
> > +     int err;
> >
> >       mtx_assert(&it->it_mtx, MA_OWNED);
> >
> > -     realtimer_clocktime(it->it_clockid, &cts);
> > +     err = kern_clock_gettime(curthread, it->it_clockid, &cts);
> > +     if (err)
> Again, if (error != 0) and s/err/error/.
> And more places below.
>
> > +             return (err);
> > +
> >       *ovalue = it->it_time;
> >       if (ovalue->it_value.tv_sec != 0 || ovalue->it_value.tv_nsec != 0) {
> >               timespecsub(&ovalue->it_value, &cts, &ovalue->it_value);
> > @@ -1594,6 +1613,7 @@ realtimer_settime(struct itimer *it, int flags, 
> > struct itimerspec *value,
> >       struct timespec cts, ts;
> >       struct timeval tv;
> >       struct itimerspec val;
> > +     int err;
> >
> >       mtx_assert(&it->it_mtx, MA_OWNED);
> >
> > @@ -1613,7 +1633,10 @@ realtimer_settime(struct itimer *it, int flags, 
> > struct itimerspec *value,
> >
> >       it->it_time = val;
> >       if (timespecisset(&val.it_value)) {
> > -             realtimer_clocktime(it->it_clockid, &cts);
> > +             err = kern_clock_gettime(curthread, it->it_clockid, &cts);
> > +             if (err)
> > +                     return (err);
> > +
> >               ts = val.it_value;
> >               if ((flags & TIMER_ABSTIME) == 0) {
> >                       /* Convert to absolute time. */
> > @@ -1636,15 +1659,6 @@ realtimer_settime(struct itimer *it, int flags, 
> > struct itimerspec *value,
> >       return (0);
> >  }
> >
> > -static void
> > -realtimer_clocktime(clockid_t id, struct timespec *ts)
> > -{
> > -     if (id == CLOCK_REALTIME)
> > -             getnanotime(ts);
> > -     else    /* CLOCK_MONOTONIC */
> > -             getnanouptime(ts);
> > -}
> > -
> >  int
> >  itimer_accept(struct proc *p, int timerid, ksiginfo_t *ksi)
> >  {
> > @@ -1689,10 +1703,12 @@ realtimer_expire_l(struct itimer *it, bool 
> > proc_locked)
> >       struct timeval tv;
> >       struct proc *p;
> >       uint64_t interval, now, overruns, value;
> > +     int err;
> > +
> > +     err = kern_clock_gettime(curthread, it->it_clockid, &cts);
> >
> > -     realtimer_clocktime(it->it_clockid, &cts);
> >       /* Only fire if time is reached. */
> > -     if (timespeccmp(&cts, &it->it_time.it_value, >=)) {
> > +     if (err == 0 && timespeccmp(&cts, &it->it_time.it_value, >=)) {
> >               if (timespecisset(&it->it_time.it_interval)) {
> >                       timespecadd(&it->it_time.it_value,
> >                           &it->it_time.it_interval,
> > diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
> > index dc6fee1f8f38..905ebd4f98ac 100644
> > --- a/sys/kern/kern_umtx.c
> > +++ b/sys/kern/kern_umtx.c
> > @@ -693,6 +693,7 @@ umtx_abs_timeout_init(struct umtx_abs_timeout *timo, 
> > int clockid,
> >               timo->is_abs_real = clockid == CLOCK_REALTIME ||
> >                   clockid == CLOCK_REALTIME_FAST ||
> >                   clockid == CLOCK_REALTIME_PRECISE ||
> > +                 clockid == CLOCK_TAI ||
> >                   clockid == CLOCK_SECOND;
> >       }
> >  }
> > @@ -787,6 +788,7 @@ umtx_abs_timeout_getsbt(struct umtx_abs_timeout *timo, 
> > sbintime_t *sbt,
> >       case CLOCK_PROF:
> >       case CLOCK_THREAD_CPUTIME_ID:
> >       case CLOCK_PROCESS_CPUTIME_ID:
> > +     case CLOCK_TAI: /* Boot time is not necessarily stable in TAI */
> >       default:
> >               kern_clock_gettime(curthread, timo->clockid, &timo->cur);
> >               if (timespeccmp(&timo->end, &timo->cur, <=))
> > @@ -2953,8 +2955,9 @@ do_cv_wait(struct thread *td, struct ucond *cv, 
> > struct umutex *m,
> >                       umtx_key_release(&uq->uq_key);
> >                       return (EFAULT);
> >               }
> > -             if (clockid < CLOCK_REALTIME ||
> > -                 clockid >= CLOCK_THREAD_CPUTIME_ID) {
> > +             if ((clockid < CLOCK_REALTIME ||
> > +                 clockid >= CLOCK_THREAD_CPUTIME_ID) &&
> > +                 clockid != CLOCK_TAI) {
> >                       /* hmm, only HW clock id will work. */
> >                       umtx_key_release(&uq->uq_key);
> >                       return (EINVAL);
> > diff --git a/sys/sys/_clock_id.h b/sys/sys/_clock_id.h
> > index 728346a0f0ab..83130d1f8a16 100644
> > --- a/sys/sys/_clock_id.h
> > +++ b/sys/sys/_clock_id.h
> > @@ -74,6 +74,10 @@
> >  #define      CLOCK_PROCESS_CPUTIME_ID 15
> >  #endif /* __POSIX_VISIBLE >= 199309 */
> >
> > +#ifdef __BSD_VISIBLE
> > +#define      CLOCK_TAI               16
> > +#endif
> > +
> >  /*
> >   * Linux compatible names.
> >   */
> > diff --git a/sys/sys/timeffc.h b/sys/sys/timeffc.h
> > index a83b62b1672c..8bec73ed48a4 100644
> > --- a/sys/sys/timeffc.h
> > +++ b/sys/sys/timeffc.h
> > @@ -89,7 +89,7 @@ extern int sysclock_active;
> >   *                   of the kernel tick timer (1/hz [s]).
> >   * FFCLOCK_LERP:     Linear interpolation of ffclock time to guarantee
> >   *                   monotonic time.
> > - * FFCLOCK_LEAPSEC:  Include leap seconds.
> > + * {FB|FF}CLOCK_LEAPSEC: Include leap seconds.
> >   * {FB|FF}CLOCK_UPTIME:      Time stamp should be relative to system boot, 
> > not epoch.
> >   */
> >  #define      FFCLOCK_FAST            0x00000001
> > @@ -100,6 +100,7 @@ extern int sysclock_active;
> >
> >  #define      FBCLOCK_FAST            0x00010000 /* Currently unused. */
> >  #define      FBCLOCK_UPTIME          0x00020000
> > +#define      FBCLOCK_LEAPSEC         0x00040000
> >  #define      FBCLOCK_MASK            0xffff0000
> >
> >  /*
> > @@ -111,6 +112,7 @@ struct fbclock_info {
> >       struct bintime          error;
> >       struct bintime          tick_time;
> >       uint64_t                th_scale;
> > +     long                    th_tai_offset;
> >       int                     status;
> >  };
> >
> > diff --git a/sys/sys/timex.h b/sys/sys/timex.h
> > index 072297375792..03632bdb119c 100644
> > --- a/sys/sys/timex.h
> > +++ b/sys/sys/timex.h
> > @@ -154,7 +154,7 @@ struct timex {
> >  #ifdef __FreeBSD__
> >
> >  #ifdef _KERNEL
> > -void ntp_update_second(int64_t *adjustment, time_t *newsec);
> > +void ntp_update_second(int64_t *adjustment, time_t *newsec, long *tai_off);
> >  #else /* !_KERNEL */
> >  #include <sys/cdefs.h>
> >

Reply via email to