https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=2abb929f0ad26dad05cbfde18fa54098dc79bbb7
commit 2abb929f0ad26dad05cbfde18fa54098dc79bbb7 Author: Corinna Vinschen <cori...@vinschen.de> AuthorDate: Wed Jul 16 16:26:42 2025 +0200 Commit: Corinna Vinschen <cori...@vinschen.de> CommitDate: Wed Jul 16 17:37:04 2025 +0200 Cygwin: clocks: Implement CLOCK_TAI CLOCK_TAI is like CLOCK_REALTIME ignoring leap secs. Right now, 2025, it has a positive 37 secs offset from CLOCK_REALTIME. Given the unpredictability of adding leap secs by the IERS (International Earth Rotation and Reference Systems Service), we also add a mechanism to read the current leap secs offset from /usr/share/zoneinfo/leapseconds, part of the tzdata package. Signed-off-by: Corinna Vinschen <cori...@vinschen.de> Diff: --- winsup/cygwin/clock.cc | 59 ++++++++++++++++++++++++++++++++++++ winsup/cygwin/local_includes/clock.h | 13 ++++++++ winsup/cygwin/posix_timer.cc | 20 +++++++++--- winsup/cygwin/release/3.7.0 | 4 +++ winsup/cygwin/signal.cc | 6 ++++ winsup/cygwin/thread.cc | 5 +++ 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/winsup/cygwin/clock.cc b/winsup/cygwin/clock.cc index dc940906edb0..c81b24ce14a6 100644 --- a/winsup/cygwin/clock.cc +++ b/winsup/cygwin/clock.cc @@ -3,6 +3,7 @@ #include "pinfo.h" #include "clock.h" #include "miscfuncs.h" +#include <stdio.h> static inline LONGLONG system_qpc_tickspersec () @@ -41,6 +42,52 @@ clk_realtime_t::init () InterlockedCompareExchange64 (&ticks_per_sec, system_qpc_tickspersec (), 0); } +uint16_t clk_tai_t::leap_secs = 0; +SRWLOCK clk_tai_t::leap_lock = SRWLOCK_INIT; + +void inline +clk_tai_t::init () +{ + if (leap_secs) + return; + + AcquireSRWLockExclusive (&leap_lock); + if (!leap_secs) + { + FILE *fp = fopen ("/usr/share/zoneinfo/leapseconds", "r"); + if (!fp) + leap_secs = 37; /* Leap secs since 2017 */ + else + { + char buf[256]; + + leap_secs = 10; /* Leap secs 1972 */ + while (fgets (buf, sizeof buf, fp)) + { + if (buf[0] != 'L') + continue; + if (strlen (buf) < 30) + continue; + switch (buf[26]) + { + case '+': + ++leap_secs; + break; + case '-': + --leap_secs; + break; + default: + break; + } + } + fclose (fp); + } + } + ReleaseSRWLockExclusive (&leap_lock); + + InterlockedCompareExchange64 (&ticks_per_sec, system_qpc_tickspersec (), 0); +} + void inline clk_monotonic_t::init () { @@ -73,6 +120,15 @@ clk_realtime_t::now (clockid_t clockid, struct timespec *ts) return 0; } +int +clk_tai_t::now (clockid_t clockid, struct timespec *ts) +{ + init (); + clk_realtime_t::now (clockid, ts); + ts->tv_sec += leap_secs; + return 0; +} + int clk_process_t::now (clockid_t clockid, struct timespec *ts) { @@ -238,6 +294,7 @@ clk_monotonic_t::resolution (struct timespec *ts) static clk_realtime_coarse_t clk_realtime_coarse; static clk_realtime_t clk_realtime; +static clk_tai_t clk_tai; static clk_process_t clk_process; static clk_thread_t clk_thread; static clk_monotonic_t clk_monotonic; @@ -259,6 +316,8 @@ clk_t *cyg_clock[MAX_CLOCKS] = &clk_boottime, &clk_realtime_alarm, &clk_boottime_alarm, + NULL, + &clk_tai, }; clk_t * diff --git a/winsup/cygwin/local_includes/clock.h b/winsup/cygwin/local_includes/clock.h index 7323299df3b5..493adf6fdff0 100644 --- a/winsup/cygwin/local_includes/clock.h +++ b/winsup/cygwin/local_includes/clock.h @@ -99,6 +99,7 @@ class clk_t now (0, &ts); return ts.tv_sec * MSPERSEC + ts.tv_nsec / (NSPERSEC/MSPERSEC); } + virtual uint16_t get_leap_secs () { return 0; } }; class clk_realtime_coarse_t : public clk_t @@ -109,11 +110,23 @@ class clk_realtime_coarse_t : public clk_t class clk_realtime_t : public clk_t { void init (); + protected: virtual int now (clockid_t, struct timespec *); public: virtual void resolution (struct timespec *); }; +class clk_tai_t : public clk_realtime_t +{ + static uint16_t leap_secs; + static SRWLOCK leap_lock; + + void init (); + virtual int now (clockid_t, struct timespec *); +public: + virtual uint16_t get_leap_secs () { init (); return leap_secs; } +}; + class clk_process_t : public clk_t { virtual int now (clockid_t, struct timespec *); diff --git a/winsup/cygwin/posix_timer.cc b/winsup/cygwin/posix_timer.cc index 14694a87dd0f..496890621943 100644 --- a/winsup/cygwin/posix_timer.cc +++ b/winsup/cygwin/posix_timer.cc @@ -349,17 +349,27 @@ timer_tracker::settime (int flags, const itimerspec *new_value, / (NSPERSEC / NS100PERSEC); if (flags & TIMER_ABSTIME) { - if (clock_id == CLOCK_REALTIME_COARSE - || clock_id == CLOCK_REALTIME - || clock_id == CLOCK_REALTIME_ALARM) - DueTime.QuadPart = ts + FACTOR; - else /* non-REALTIME clocks require relative DueTime. */ + switch (clock_id) { + case CLOCK_REALTIME_COARSE: + case CLOCK_REALTIME: + case CLOCK_REALTIME_ALARM: + case CLOCK_TAI: + DueTime.QuadPart = ts + FACTOR; + /* TAI time is realtime + leap secs. NT timers are on + realtime. Subtract leap secs to get the corresponding + real due time. Leap secs are always 0 unless CLOCK_TAI. */ + DueTime.QuadPart -= get_clock (clock_id)->get_leap_secs () + * NS100PERSEC; + break; + default: + /* non-REALTIME clocks require relative DueTime. */ DueTime.QuadPart = get_clock_now () - ts; /* If the timestamp was earlier than now, compute number of expirations and offset DueTime to expire immediately. */ if (DueTime.QuadPart >= 0) DueTime.QuadPart = -1LL; + break; } } else diff --git a/winsup/cygwin/release/3.7.0 b/winsup/cygwin/release/3.7.0 new file mode 100644 index 000000000000..7aa3c9384a31 --- /dev/null +++ b/winsup/cygwin/release/3.7.0 @@ -0,0 +1,4 @@ +What's new: +----------- + +- Support for CLOCK_TAI clock and timer. diff --git a/winsup/cygwin/signal.cc b/winsup/cygwin/signal.cc index f8ba67e7547c..544f9489e721 100644 --- a/winsup/cygwin/signal.cc +++ b/winsup/cygwin/signal.cc @@ -112,7 +112,13 @@ clock_nanosleep (clockid_t clk_id, int flags, const struct timespec *rqtp, { case CLOCK_REALTIME_COARSE: case CLOCK_REALTIME: + case CLOCK_TAI: timeout.QuadPart += FACTOR; + /* TAI time is realtime + leap secs. NT timers are on realtime. + Subtract leap secs to get the corresponding real due time. + Leap secs are always 0 unless CLOCK_TAI. */ + timeout.QuadPart -= get_clock (clk_id)->get_leap_secs () + * NS100PERSEC; break; default: /* other clocks need to be handled with a relative timeout */ diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index b462e2f9f95d..86a00e76e3b9 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -2361,7 +2361,12 @@ pthread_convert_abstime (clockid_t clock_id, const struct timespec *abstime, { case CLOCK_REALTIME_COARSE: case CLOCK_REALTIME: + case CLOCK_TAI: timeout->QuadPart += FACTOR; + /* TAI time is realtime + leap secs. NT timers are on realtime. + Subtract leap secs to get the corresponding real due time. + Leap secs are always 0 unless CLOCK_TAI. */ + timeout->QuadPart -= get_clock (clock_id)->get_leap_secs () * NS100PERSEC; break; default: /* other clocks must be handled as relative timeout */