[newlib-cygwin/main] Cygwin: clocks: Implement CLOCK_TAI
Corinna Vinschen
corinna@sourceware.org
Wed Jul 16 15:38:44 GMT 2025
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=2abb929f0ad26dad05cbfde18fa54098dc79bbb7
commit 2abb929f0ad26dad05cbfde18fa54098dc79bbb7
Author: Corinna Vinschen <corinna@vinschen.de>
AuthorDate: Wed Jul 16 16:26:42 2025 +0200
Commit: Corinna Vinschen <corinna@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 <corinna@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 */
More information about the Cygwin-cvs
mailing list