aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2025-07-16 16:26:42 +0200
committerCorinna Vinschen <corinna@vinschen.de>2025-07-16 17:37:04 +0200
commit2abb929f0ad26dad05cbfde18fa54098dc79bbb7 (patch)
tree18a979cf2bee2e51ac6a5933baf1ec0e955bf3f1
parente8bc312a2d32a465260e38f948d91f2847a1d00a (diff)
downloadnewlib-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.cc59
-rw-r--r--winsup/cygwin/local_includes/clock.h13
-rw-r--r--winsup/cygwin/posix_timer.cc20
-rw-r--r--winsup/cygwin/release/3.7.04
-rw-r--r--winsup/cygwin/signal.cc6
-rw-r--r--winsup/cygwin/thread.cc5
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 */