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 */

Reply via email to