diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2025-07-16 16:26:42 +0200 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2025-07-16 17:37:04 +0200 |
commit | 2abb929f0ad26dad05cbfde18fa54098dc79bbb7 (patch) | |
tree | 18a979cf2bee2e51ac6a5933baf1ec0e955bf3f1 | |
parent | e8bc312a2d32a465260e38f948d91f2847a1d00a (diff) | |
download | newlib-2abb929f0ad26dad05cbfde18fa54098dc79bbb7.zip newlib-2abb929f0ad26dad05cbfde18fa54098dc79bbb7.tar.gz newlib-2abb929f0ad26dad05cbfde18fa54098dc79bbb7.tar.bz2 |
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 <corinna@vinschen.de>
-rw-r--r-- | winsup/cygwin/clock.cc | 59 | ||||
-rw-r--r-- | winsup/cygwin/local_includes/clock.h | 13 | ||||
-rw-r--r-- | winsup/cygwin/posix_timer.cc | 20 | ||||
-rw-r--r-- | winsup/cygwin/release/3.7.0 | 4 | ||||
-rw-r--r-- | winsup/cygwin/signal.cc | 6 | ||||
-rw-r--r-- | 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 dc94090..c81b24c 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 () { @@ -74,6 +121,15 @@ clk_realtime_t::now (clockid_t clockid, struct timespec *ts) } 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) { pid_t pid = CLOCKID_TO_PID (clockid); @@ -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 7323299..493adf6 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 14694a8..4968906 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 0000000..7aa3c93 --- /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 f8ba67e..544f948 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 b462e2f..86a00e7 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 */ |