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, but without leap seconds. +It 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/libsys/timer_create.2 b/lib/libsys/timer_create.2 --- a/lib/libsys/timer_create.2 +++ b/lib/libsys/timer_create.2 @@ -126,7 +126,8 @@ 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 --- 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 @@ -504,7 +504,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 +624,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; @@ -1066,6 +1067,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 +1141,11 @@ 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 @@ 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 @@ -60,7 +61,7 @@ #include #include -#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_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 @@ 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 +332,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 +462,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 +527,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: @@ -1143,6 +1156,7 @@ 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); @@ -1303,6 +1317,7 @@ switch (clock_id) { default: case CLOCK_REALTIME: + case CLOCK_TAI: it->it_sigev.sigev_signo = SIGALRM; break; case CLOCK_VIRTUAL: @@ -1546,10 +1561,14 @@ 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) + 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); @@ -1570,6 +1589,7 @@ struct timespec cts, ts; struct timeval tv; struct itimerspec val; + int err; mtx_assert(&it->it_mtx, MA_OWNED); @@ -1589,7 +1609,10 @@ 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. */ @@ -1612,15 +1635,6 @@ 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) { @@ -1665,10 +1679,12 @@ 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 --- 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, <=)) @@ -2945,8 +2947,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