Date: Fri, 13 Jun 2025 10:36:21 -0400 From: Warner Losh <imp@bsdimp.com> To: Konstantin Belousov <kostikbel@gmail.com> Cc: Warner Losh <imp@freebsd.org>, src-committers@freebsd.org, dev-commits-src-all@freebsd.org, dev-commits-src-main@freebsd.org Subject: Re: git: 7b7ba7857ce8 - main - Implement CLOCK_TAI Message-ID: <CANCZdfpnp1Wd_u1NUZx32=ouW8q3BFKT%2BmuKQc8zoOpxLSoVBQ@mail.gmail.com> In-Reply-To: <aEvCgKpiu-obZtxo@kib.kiev.ua> References: <202506121825.55CIPemP006355@gitrepo.freebsd.org> <aEvCgKpiu-obZtxo@kib.kiev.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
Ah, good feedback. Applied in bd8621c6cd8a. Anything else? Warner On Fri, Jun 13, 2025 at 2:17=E2=80=AFAM Konstantin Belousov <kostikbel@gmai= l.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=3D7b7ba7857ce8be0bf6ab905d= 936d8ba1363e4ec2 > > > > commit 7b7ba7857ce8be0bf6ab905d936d8ba1363e4ec2 > > Author: Nathan Whitehorn <nwhitehorn@FreeBSD.org> > > AuthorDate: 2025-06-12 17:52:30 +0000 > > Commit: Warner Losh <imp@FreeBSD.org> > > CommitDate: 2025-06-12 18:25:31 +0000 > > > > Implement CLOCK_TAI > > > > Provide a clock through clock_gettime() that returns the current TA= I > > 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 ac= quire > > TAI time. Unlike Linux, this code will return EINVAL if the TAI off= set > > (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 no= t > > 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 POSSIBILIT= Y 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 curre= nt 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 kn= own, > .Er EINVAL > > +which may be the case early in boot before NTP or other time daemon ha= s > > +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 POSSIBILIT= Y 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_c= ondattr.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 =3D=3D NULL || *attr =3D=3D NULL) > > return (EINVAL); > > if (clock_id !=3D CLOCK_REALTIME && > > + clock_id !=3D CLOCK_TAI && > > clock_id !=3D CLOCK_VIRTUAL && > > clock_id !=3D CLOCK_PROF && > > clock_id !=3D 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_adjti= me_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 *news= ec) > > L_ADD(time_adj, ftemp); > > } > > *adjustment =3D time_adj; > > + *tai_off =3D 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 =3D timehands; > > gen =3D atomic_load_acq_int(&th->th_generation); > > fbi->th_scale =3D th->th_scale; > > + fbi->th_tai_offset =3D th->th_tai_offset; > > fbi->tick_time =3D th->th_offset; > > #ifdef FFCLOCK > > ffth =3D 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 =3D=3D 0) > > + return (EINVAL); > > + bt->sec +=3D cs->fb_info.th_tai_offset; > > + } > > break; > > #ifdef FFCLOCK > > case SYSCLOCK_FFWD: > > @@ -1433,7 +1440,8 @@ tc_windup(struct bintime *new_boottimebin) > > > > do { > > t =3D 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 !=3D t) > > th->th_boottime.sec +=3D 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 times= pec *ats) > > { > > struct timeval sys, user; > > + struct sysclock_snap clk; > > + struct bintime bt; > > struct proc *p; > > + int err; > We usually spell it as 'error'. > > > > > p =3D td->td_proc; > > switch (clock_id) { > > @@ -329,6 +332,14 @@ kern_clock_gettime(struct thread *td, clockid_t cl= ock_id, struct timespec *ats) > > case CLOCK_REALTIME_FAST: > > getnanotime(ats); > > break; > > + case CLOCK_TAI: > > + sysclock_getsnapshot(&clk, 0); > > + err =3D sysclock_snap2bintime(&clk, &bt, clk.sysclock_act= ive, > > + (clk.sysclock_active =3D=3D SYSCLOCK_FFWD) ? FFCLOCK_= LERP : 0); > Extra () > > > + if (err) > if (err !=3D 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 cloc= k_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 c= lock_id, int flags, > > return (EINVAL); > > switch (clock_id) { > > case CLOCK_REALTIME: > > + case CLOCK_TAI: > > precise =3D nanosleep_precise; > > is_abs_real =3D (flags & TIMER_ABSTIME) !=3D 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 c= lock_id, struct sigevent *evp, > > switch (clock_id) { > > default: > > case CLOCK_REALTIME: > > + case CLOCK_TAI: > > it->it_sigev.sigev_signo =3D 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 =3D kern_clock_gettime(curthread, it->it_clockid, &cts); > > + if (err) > Again, if (error !=3D 0) and s/err/error/. > And more places below. > > > + return (err); > > + > > *ovalue =3D it->it_time; > > if (ovalue->it_value.tv_sec !=3D 0 || ovalue->it_value.tv_nsec != =3D 0) { > > timespecsub(&ovalue->it_value, &cts, &ovalue->it_value); > > @@ -1594,6 +1613,7 @@ realtimer_settime(struct itimer *it, int flags, s= truct 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 =3D val; > > if (timespecisset(&val.it_value)) { > > - realtimer_clocktime(it->it_clockid, &cts); > > + err =3D kern_clock_gettime(curthread, it->it_clockid, &ct= s); > > + if (err) > > + return (err); > > + > > ts =3D val.it_value; > > if ((flags & TIMER_ABSTIME) =3D=3D 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 =3D=3D 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 =3D 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, >=3D)) { > > + if (err =3D=3D 0 && timespeccmp(&cts, &it->it_time.it_value, >=3D= )) { > > 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 =3D clockid =3D=3D CLOCK_REALTIME || > > clockid =3D=3D CLOCK_REALTIME_FAST || > > clockid =3D=3D CLOCK_REALTIME_PRECISE || > > + clockid =3D=3D CLOCK_TAI || > > clockid =3D=3D CLOCK_SECOND; > > } > > } > > @@ -787,6 +788,7 @@ umtx_abs_timeout_getsbt(struct umtx_abs_timeout *ti= mo, 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, <=3D)) > > @@ -2953,8 +2955,9 @@ do_cv_wait(struct thread *td, struct ucond *cv, s= truct umutex *m, > > umtx_key_release(&uq->uq_key); > > return (EFAULT); > > } > > - if (clockid < CLOCK_REALTIME || > > - clockid >=3D CLOCK_THREAD_CPUTIME_ID) { > > + if ((clockid < CLOCK_REALTIME || > > + clockid >=3D CLOCK_THREAD_CPUTIME_ID) && > > + clockid !=3D 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 >=3D 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 b= oot, 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> > >
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CANCZdfpnp1Wd_u1NUZx32=ouW8q3BFKT%2BmuKQc8zoOpxLSoVBQ>