diff --git a/lib/libsys/_umtx_op.2 b/lib/libsys/_umtx_op.2 --- a/lib/libsys/_umtx_op.2 +++ b/lib/libsys/_umtx_op.2 @@ -210,6 +210,8 @@ .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 --- 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 @@ 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, except does not include leap seconds and will +increase monotonically during a leap second. +Will return EINVAL if the current offset between TAI and UTC is not known, +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 @@ .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 --- 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 3, 2022 +.Dd August 10, 2024 .Dt NANOSLEEP 2 .Os .Sh NAME @@ -124,6 +124,8 @@ .It CLOCK_SECOND .It +CLOCK_TAI +.It CLOCK_UPTIME .It CLOCK_UPTIME_FAST diff --git a/lib/libthr/thread/thr_condattr.c b/lib/libthr/thread/thr_condattr.c --- a/lib/libthr/thread/thr_condattr.c +++ b/lib/libthr/thread/thr_condattr.c @@ -94,6 +94,7 @@ 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 --- a/share/man/man3/pthread_condattr.3 +++ b/share/man/man3/pthread_condattr.3 @@ -85,7 +85,8 @@ .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 --- a/sys/kern/kern_ntptime.c +++ b/sys/kern/kern_ntptime.c @@ -154,6 +154,7 @@ static int time_state = TIME_OK; /* clock state */ int time_status = STA_UNSYNC; /* clock status bits */ static long time_tai; /* TAI offset (s) */ +bool time_tai_set = false; /* Whether time_tai has been set */ static long time_monitor; /* last time offset scaled (ns) */ static long time_constant; /* poll interval (shift) (s) */ static long time_precision = 1; /* clock precision (ns) */ @@ -388,8 +389,10 @@ time_constant = ntv->constant; } if (modes & MOD_TAI) { - if (ntv->constant > 0) /* XXX zero & negative numbers ? */ + if (ntv->constant > 0) { /* XXX zero & negative numbers ? */ time_tai = ntv->constant; + time_tai_set = true; + } } #ifdef PPS_SYNC if (modes & MOD_PPSMAX) { @@ -504,7 +507,7 @@ * 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 +627,7 @@ 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 --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -72,6 +72,7 @@ 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; @@ -1038,6 +1039,7 @@ /* Internal NTP status and error estimates. */ extern int time_status; extern long time_esterror; +extern bool time_tai_set; /* * Take a snapshot of sysclock data which can be used to compare system clocks @@ -1066,6 +1068,7 @@ 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 +1142,11 @@ getboottimebin(&boottimebin); bintime_add(bt, &boottimebin); } + if (!(flags & FBCLOCK_LEAPSEC)) { + if (!time_tai_set) + return (EINVAL); + bt->sec += cs->fb_info.th_tai_offset; + } break; #ifdef FFCLOCK case SYSCLOCK_FFWD: @@ -1433,7 +1441,8 @@ 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 --- a/sys/kern/kern_time.c +++ b/sys/kern/kern_time.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -318,7 +319,10 @@ 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; p = td->td_proc; switch (clock_id) { @@ -329,6 +333,14 @@ 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); + if (err) + return (err); + bintime2timespec(&bt, ats); + break; case CLOCK_VIRTUAL: PROC_LOCK(p); PROC_STATLOCK(p); @@ -451,6 +463,7 @@ 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: @@ -515,6 +528,7 @@ case CLOCK_REALTIME_PRECISE: case CLOCK_REALTIME_FAST: case CLOCK_SECOND: + case CLOCK_TAI: is_abs_real = (flags & TIMER_ABSTIME) != 0; break; case CLOCK_MONOTONIC: diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -686,6 +686,7 @@ timo->is_abs_real = clockid == CLOCK_REALTIME || clockid == CLOCK_REALTIME_FAST || clockid == CLOCK_REALTIME_PRECISE || + clockid == CLOCK_TAI || clockid == CLOCK_SECOND; } } @@ -780,6 +781,7 @@ 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, <=)) @@ -2944,8 +2946,9 @@ 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 --- 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 --- a/sys/sys/timeffc.h +++ b/sys/sys/timeffc.h @@ -89,7 +89,7 @@ * 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 @@ #define FBCLOCK_FAST 0x00010000 /* Currently unused. */ #define FBCLOCK_UPTIME 0x00020000 +#define FBCLOCK_LEAPSEC 0x00040000 #define FBCLOCK_MASK 0xffff0000 /* @@ -111,6 +112,7 @@ 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 --- a/sys/sys/timex.h +++ b/sys/sys/timex.h @@ -154,7 +154,7 @@ #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